///|
struct RendererHandle {
mut size : @core.Size
mut physical_size : @core.Size
mut scale_factor : Double
mut last_batches : Array[@render.RectBatch]
mut configured : Bool
mut present_count : Int
mut surface_format : @wgpu_mbt.TextureFormat
mut instance : @wgpu_mbt.Instance?
mut adapter : @wgpu_mbt.Adapter?
mut device : @wgpu_mbt.Device?
mut queue : @wgpu_mbt.Queue?
mut surface : @wgpu_mbt.Surface?
mut visual_shader : @wgpu_mbt.ShaderModule?
mut visual_pipeline : @wgpu_mbt.RenderPipeline?
mut visual_vertex_buffer : @wgpu_mbt.Buffer?
mut text_shader : @wgpu_mbt.ShaderModule?
mut text_pipeline : @wgpu_mbt.RenderPipeline?
mut text_vertex_buffer : @wgpu_mbt.Buffer?
mut text_atlas_texture : @wgpu_mbt.Texture?
mut text_atlas_view : @wgpu_mbt.TextureView?
mut text_sampler : @wgpu_mbt.Sampler?
mut text_bind_group_layout : @wgpu_mbt.BindGroupLayout?
mut text_pipeline_layout : @wgpu_mbt.PipelineLayout?
mut text_bind_group : @wgpu_mbt.BindGroup?
mut image_shader : @wgpu_mbt.ShaderModule?
mut image_pipeline : @wgpu_mbt.RenderPipeline?
mut image_vertex_buffer : @wgpu_mbt.Buffer?
mut image_sampler : @wgpu_mbt.Sampler?
mut image_bind_group_layout : @wgpu_mbt.BindGroupLayout?
mut image_pipeline_layout : @wgpu_mbt.PipelineLayout?
mut advanced_shader : @wgpu_mbt.ShaderModule?
mut advanced_pipeline_source_over : @wgpu_mbt.RenderPipeline?
mut advanced_pipeline_multiply : @wgpu_mbt.RenderPipeline?
mut advanced_pipeline_screen : @wgpu_mbt.RenderPipeline?
mut advanced_pipeline_overlay : @wgpu_mbt.RenderPipeline?
mut advanced_pipeline_darken : @wgpu_mbt.RenderPipeline?
mut advanced_pipeline_lighten : @wgpu_mbt.RenderPipeline?
mut advanced_vertex_buffer : @wgpu_mbt.Buffer?
mut advanced_sampler : @wgpu_mbt.Sampler?
mut advanced_bind_group_layout : @wgpu_mbt.BindGroupLayout?
mut advanced_pipeline_layout : @wgpu_mbt.PipelineLayout?
mut advanced_overlay_bind_group_layout : @wgpu_mbt.BindGroupLayout?
mut advanced_overlay_pipeline_layout : @wgpu_mbt.PipelineLayout?
mut white_texture : @wgpu_mbt.Texture?
mut white_view : @wgpu_mbt.TextureView?
mut white_bind_group : @wgpu_mbt.BindGroup?
image_cache : Map[String, NativeImageResource]
decoded_image_cache : Map[String, NativeDecodedImage]
failed_images : Map[String, Bool]
image_lifecycle : @render_common.ImageResourceLifecycle
font_cache : NativeFontCache
glyph_atlas : GlyphAtlas
mut visual_vertices : Array[VisualVertex]
mut text_vertices : Array[TextVertex]
mut image_vertices : Array[ImageVertex]
mut draw_items : Array[NativeDrawItem]
mut text_atlas_dirty : Bool
mut unsupported_command_count : Int
}
///|
priv struct NativeOffscreenTexture {
texture : @wgpu_mbt.Texture
view : @wgpu_mbt.TextureView
bind_group : @wgpu_mbt.BindGroup
}
///|
priv struct NativeBackdropTexture {
texture : @wgpu_mbt.Texture
view : @wgpu_mbt.TextureView
bind_group : @wgpu_mbt.BindGroup
}
///|
priv struct NativePlanGpuBuffers {
visual_buffer : @wgpu_mbt.Buffer?
text_buffer : @wgpu_mbt.Buffer?
image_buffer : @wgpu_mbt.Buffer?
visual_size : UInt64
text_size : UInt64
image_size : UInt64
}
///|
fn RendererHandle::create_with_host_surface(
metrics : @core.SurfaceMetrics,
host_surface : HostWgpuSurface,
) -> RendererHandle raise @wgpu_mbt.WgpuError {
create_with_surface(
metrics,
host_surface.instance(),
host_surface.surface(),
native_noop_text_engine(),
)
}
///|
fn RendererHandle::create_with_host_surface_and_text_engine(
metrics : @core.SurfaceMetrics,
host_surface : HostWgpuSurface,
text_engine : NativeTextEngine,
) -> RendererHandle raise @wgpu_mbt.WgpuError {
create_with_surface(
metrics,
host_surface.instance(),
host_surface.surface(),
text_engine,
)
}
///|
///|
/// Prefer non-sRGB surface formats so sRGB palette bytes (e.g. `ColorPalette::light()`
/// primary `0.145`) are presented verbatim. `configure_default` picks
/// `caps.formats[0]` which is `BGRA8UnormSrgb` on macOS/Metal; the fragment
/// shaders output sRGB directly (`visual_shader_wgsl` / `text_shader_wgsl`)
/// and a Srgb target would then apply a spurious `linear->sRGB` encode
/// (`0.145 -> ~0.39`) washing the UI as seen in the Skia vs WGPU showcase
/// comparison. Keep blending in sRGB (matching Skia's `raster_n32_premul` +
/// `NSImageView` path) by forcing `BGRA8Unorm`/`RGBA8Unorm`.
fn wgpu_is_srgb_format(format : @wgpu_mbt.TextureFormat) -> Bool {
format.raw == @wgpu_mbt.TEXTURE_FORMAT_BGRA8_UNORM_SRGB ||
format.raw == @wgpu_mbt.TEXTURE_FORMAT_RGBA8_UNORM_SRGB
}
///|
fn wgpu_contains_format(
formats : Array[@wgpu_mbt.TextureFormat],
target : @wgpu_mbt.TextureFormat,
) -> Bool {
for fmt in formats {
if fmt.raw == target.raw {
return true
}
}
false
}
///|
fn wgpu_contains_u32(values : Array[UInt], target : UInt) -> Bool {
for v in values {
if v == target {
return true
}
}
false
}
///|
fn wgpu_pick_preferred_surface_format(
surface : @wgpu_mbt.Surface,
adapter : @wgpu_mbt.Adapter,
) -> @wgpu_mbt.TextureFormat {
let formats = surface.capabilities_formats(adapter)
let prefs = [
@wgpu_mbt.TextureFormat::from_u32(@wgpu_mbt.TEXTURE_FORMAT_BGRA8_UNORM),
@wgpu_mbt.TextureFormat::from_u32(@wgpu_mbt.TEXTURE_FORMAT_RGBA8_UNORM),
]
for pref in prefs {
if wgpu_contains_format(formats, pref) {
return pref
}
}
for fmt in formats {
if !wgpu_is_srgb_format(fmt) {
return fmt
}
}
if formats.length() > 0 {
let first = formats[0]
if wgpu_is_srgb_format(first) {
if first.raw == @wgpu_mbt.TEXTURE_FORMAT_BGRA8_UNORM_SRGB {
let alt = @wgpu_mbt.TextureFormat::from_u32(
@wgpu_mbt.TEXTURE_FORMAT_BGRA8_UNORM,
)
if wgpu_contains_format(formats, alt) {
return alt
}
} else if first.raw == @wgpu_mbt.TEXTURE_FORMAT_RGBA8_UNORM_SRGB {
let alt = @wgpu_mbt.TextureFormat::from_u32(
@wgpu_mbt.TEXTURE_FORMAT_RGBA8_UNORM,
)
if wgpu_contains_format(formats, alt) {
return alt
}
}
}
return first
}
@wgpu_mbt.TextureFormat::from_u32(@wgpu_mbt.TEXTURE_FORMAT_BGRA8_UNORM)
}
///|
fn wgpu_configure_surface_preferred(
surface : @wgpu_mbt.Surface,
adapter : @wgpu_mbt.Adapter,
device : @wgpu_mbt.Device,
width : UInt,
height : UInt,
usage : @wgpu_mbt.TextureUsage,
) -> @wgpu_mbt.TextureFormat {
let format = wgpu_pick_preferred_surface_format(surface, adapter)
let present_modes = surface.capabilities_present_modes(adapter)
let alpha_modes = surface.capabilities_alpha_modes(adapter)
let mut present_mode = @wgpu_mbt.PRESENT_MODE_FIFO
let present_prefs = [
@wgpu_mbt.PRESENT_MODE_FIFO,
@wgpu_mbt.PRESENT_MODE_FIFO_RELAXED,
]
for pref in present_prefs {
if wgpu_contains_u32(present_modes, pref) {
present_mode = pref
break
}
}
if !wgpu_contains_u32(present_modes, present_mode) &&
present_modes.length() > 0 {
present_mode = present_modes[0]
}
let mut alpha_mode = @wgpu_mbt.COMPOSITE_ALPHA_MODE_AUTO
let alpha_prefs = [
@wgpu_mbt.COMPOSITE_ALPHA_MODE_AUTO,
@wgpu_mbt.COMPOSITE_ALPHA_MODE_OPAQUE,
@wgpu_mbt.COMPOSITE_ALPHA_MODE_PREMULTIPLIED,
@wgpu_mbt.COMPOSITE_ALPHA_MODE_UNPREMULTIPLIED,
@wgpu_mbt.COMPOSITE_ALPHA_MODE_INHERIT,
]
for pref in alpha_prefs {
if wgpu_contains_u32(alpha_modes, pref) {
alpha_mode = pref
break
}
}
if !wgpu_contains_u32(alpha_modes, alpha_mode) && alpha_modes.length() > 0 {
alpha_mode = alpha_modes[0]
}
let supported_usage = surface.capabilities_usages_u64(adapter)
let actual_usage_raw = if (usage.raw & supported_usage.raw) == 0UL {
supported_usage.raw
} else {
usage.raw & supported_usage.raw
}
let actual_usage = @wgpu_mbt.TextureUsage::from_u64(actual_usage_raw)
let ok = surface.configure_u32(
adapter, device, width, height, actual_usage, format, present_mode, alpha_mode,
)
if ok {
return format
}
surface.configure_default(adapter, device, width, height, usage)
}
///|
fn create_with_surface(
metrics : @core.SurfaceMetrics,
instance : @wgpu_mbt.Instance,
surface : @wgpu_mbt.Surface,
text_engine : NativeTextEngine,
) -> RendererHandle raise @wgpu_mbt.WgpuError {
let adapter = instance.request_adapter_sync_options_surface_u32(surface)
let device = adapter.request_device_sync(instance)
let queue = device.queue()
let usage = @wgpu_mbt.TextureUsage::from_u64(
@wgpu_mbt.TEXTURE_USAGE_RENDER_ATTACHMENT | @wgpu_mbt.TEXTURE_USAGE_COPY_SRC,
)
let format = wgpu_configure_surface_preferred(
surface,
adapter,
device,
@render.size_dim_to_uint(metrics.physical_size.width),
@render.size_dim_to_uint(metrics.physical_size.height),
usage,
)
let visual_shader = device.create_shader_module_wgsl(visual_shader_wgsl())
let visual_pipeline = create_visual_pipeline(device, visual_shader, format)
let text_shader = device.create_shader_module_wgsl(text_shader_wgsl())
let text_bind_group_layout = device.create_bind_group_layout_sampler_texture_2d()
let text_pipeline_layout = device.create_pipeline_layout_1(
text_bind_group_layout,
)
let text_pipeline = create_text_pipeline(
device, text_shader, format, text_pipeline_layout,
)
let text_usage = @wgpu_mbt.TextureUsage::from_u64(
@wgpu_mbt.TEXTURE_USAGE_TEXTURE_BINDING | @wgpu_mbt.TEXTURE_USAGE_COPY_DST,
)
let text_atlas_texture = device.create_texture_rgba8_2d_with_usage(
atlas_width.reinterpret_as_uint(),
atlas_height.reinterpret_as_uint(),
text_usage,
)
let text_atlas_view = text_atlas_texture.create_view()
let text_sampler = device.create_sampler_nearest_clamp()
let text_bind_group = device.create_bind_group_sampler_texture_2d(
text_bind_group_layout, text_sampler, text_atlas_view,
)
let image_shader = device.create_shader_module_wgsl(image_shader_wgsl())
let image_bind_group_layout = device.create_bind_group_layout_sampler_texture_2d()
let image_pipeline_layout = device.create_pipeline_layout_1(
image_bind_group_layout,
)
let image_pipeline = create_image_pipeline(
device, image_shader, format, image_pipeline_layout,
)
let image_sampler = device.create_sampler_linear_clamp()
let advanced_shader = device.create_shader_module_wgsl(advanced_shader_wgsl())
let advanced_bind_group_layout = create_advanced_overlay_bind_group_layout(
device,
)
let advanced_pipeline_layout = device.create_pipeline_layout_1(
advanced_bind_group_layout,
)
let advanced_overlay_bind_group_layout = create_advanced_overlay_bind_group_layout(
device,
)
let advanced_overlay_pipeline_layout = device.create_pipeline_layout_1(
advanced_overlay_bind_group_layout,
)
let advanced_pipeline_source_over = create_advanced_pipeline(
device,
advanced_shader,
format,
advanced_pipeline_layout,
@core.BlendMode::SourceOver,
)
let advanced_pipeline_multiply = create_advanced_pipeline(
device,
advanced_shader,
format,
advanced_pipeline_layout,
@core.BlendMode::Multiply,
)
let advanced_pipeline_screen = create_advanced_pipeline(
device,
advanced_shader,
format,
advanced_pipeline_layout,
@core.BlendMode::Screen,
)
let advanced_pipeline_overlay = create_advanced_overlay_pipeline(
device, advanced_shader, format, advanced_overlay_pipeline_layout,
)
let advanced_pipeline_darken = create_advanced_pipeline(
device,
advanced_shader,
format,
advanced_pipeline_layout,
@core.BlendMode::Darken,
)
let advanced_pipeline_lighten = create_advanced_pipeline(
device,
advanced_shader,
format,
advanced_pipeline_layout,
@core.BlendMode::Lighten,
)
let advanced_sampler = device.create_sampler_linear_clamp()
let white_usage = @wgpu_mbt.TextureUsage::from_u64(
@wgpu_mbt.TEXTURE_USAGE_TEXTURE_BINDING | @wgpu_mbt.TEXTURE_USAGE_COPY_DST,
)
let white_texture = device.create_texture_rgba8_2d_with_usage(
1U, 1U, white_usage,
)
queue.write_texture_rgba8_2d(
white_texture,
1U,
1U,
Bytes::from_array([b'\xff', b'\xff', b'\xff', b'\xff']),
)
let white_view = white_texture.create_view()
let white_bind_group = create_advanced_bind_group(
device, advanced_bind_group_layout, advanced_sampler, white_view, white_view,
)
{
size: metrics.logical_size,
physical_size: metrics.physical_size,
scale_factor: metrics.scale_factor,
last_batches: [],
configured: true,
present_count: 0,
surface_format: format,
instance: Some(instance),
adapter: Some(adapter),
device: Some(device),
queue: Some(queue),
surface: Some(surface),
visual_shader: Some(visual_shader),
visual_pipeline: Some(visual_pipeline),
visual_vertex_buffer: None,
text_shader: Some(text_shader),
text_pipeline: Some(text_pipeline),
text_vertex_buffer: None,
text_atlas_texture: Some(text_atlas_texture),
text_atlas_view: Some(text_atlas_view),
text_sampler: Some(text_sampler),
text_bind_group_layout: Some(text_bind_group_layout),
text_pipeline_layout: Some(text_pipeline_layout),
text_bind_group: Some(text_bind_group),
image_shader: Some(image_shader),
image_pipeline: Some(image_pipeline),
image_vertex_buffer: None,
image_sampler: Some(image_sampler),
image_bind_group_layout: Some(image_bind_group_layout),
image_pipeline_layout: Some(image_pipeline_layout),
advanced_shader: Some(advanced_shader),
advanced_pipeline_source_over: Some(advanced_pipeline_source_over),
advanced_pipeline_multiply: Some(advanced_pipeline_multiply),
advanced_pipeline_screen: Some(advanced_pipeline_screen),
advanced_pipeline_overlay: Some(advanced_pipeline_overlay),
advanced_pipeline_darken: Some(advanced_pipeline_darken),
advanced_pipeline_lighten: Some(advanced_pipeline_lighten),
advanced_vertex_buffer: None,
advanced_sampler: Some(advanced_sampler),
advanced_bind_group_layout: Some(advanced_bind_group_layout),
advanced_pipeline_layout: Some(advanced_pipeline_layout),
advanced_overlay_bind_group_layout: Some(advanced_overlay_bind_group_layout),
advanced_overlay_pipeline_layout: Some(advanced_overlay_pipeline_layout),
white_texture: Some(white_texture),
white_view: Some(white_view),
white_bind_group: Some(white_bind_group),
image_cache: Map([]),
decoded_image_cache: Map([]),
failed_images: Map([]),
image_lifecycle: @render_common.ImageResourceLifecycle::new(),
font_cache: NativeFontCache::new_with_engine(text_engine),
glyph_atlas: GlyphAtlas::new(width=atlas_width, height=atlas_height),
visual_vertices: [],
text_vertices: [],
image_vertices: [],
draw_items: [],
text_atlas_dirty: true,
unsupported_command_count: 0,
}
}
///|
fn RendererHandle::resize(
self : RendererHandle,
metrics : @core.SurfaceMetrics,
) -> Unit {
let scale_changed = self.scale_factor != metrics.scale_factor
self.size = metrics.logical_size
self.physical_size = metrics.physical_size
self.scale_factor = metrics.scale_factor
if scale_changed {
self.glyph_atlas.clear()
}
let physical_size = self.effective_physical_size()
match (self.surface, self.adapter, self.device) {
(Some(surface), Some(adapter), Some(device)) => {
let usage = @wgpu_mbt.TextureUsage::from_u64(
@wgpu_mbt.TEXTURE_USAGE_RENDER_ATTACHMENT |
@wgpu_mbt.TEXTURE_USAGE_COPY_SRC,
)
self.surface_format = wgpu_configure_surface_preferred(
surface,
adapter,
device,
@render.size_dim_to_uint(physical_size.width),
@render.size_dim_to_uint(physical_size.height),
usage,
)
self.configured = true
}
_ => ()
}
}
///|
fn RendererHandle::effective_physical_size(self : RendererHandle) -> @core.Size {
if self.physical_size.width > 0.0 && self.physical_size.height > 0.0 {
self.physical_size
} else {
@core.Size::new(
width=self.size.width * self.scale_factor,
height=self.size.height * self.scale_factor,
)
}
}
///|
fn RendererHandle::render(
self : RendererHandle,
commands : Array[@core.DrawCommand],
) -> Unit {
self.last_batches = @render.collect_rect_batches(commands)
self.record_native_image_commands(commands)
let lowered = @render_common.lower_draw_commands(commands)
let plan = build_native_draw_plan(
self.font_cache,
self.glyph_atlas,
lowered.ops,
self.size,
self.scale_factor,
)
self.visual_vertices = plan.visual_vertices
self.text_vertices = plan.text_vertices
self.image_vertices = plan.image_vertices
self.draw_items = plan.items
self.text_atlas_dirty = plan.atlas_dirty
self.unsupported_command_count = count_native_unsupported_commands(commands)
self.render_wgpu(commands)
}
///|
fn RendererHandle::dispose(self : RendererHandle) -> Unit {
match self.visual_vertex_buffer {
Some(buffer) => buffer.release()
None => ()
}
match self.text_vertex_buffer {
Some(buffer) => buffer.release()
None => ()
}
match self.image_vertex_buffer {
Some(buffer) => buffer.release()
None => ()
}
for resource in self.image_cache.values() {
resource.release()
}
self.image_cache.clear()
self.decoded_image_cache.clear()
self.failed_images.clear()
match self.image_pipeline {
Some(pipeline) => pipeline.release()
None => ()
}
match self.image_pipeline_layout {
Some(layout) => layout.release()
None => ()
}
match self.image_bind_group_layout {
Some(layout) => layout.release()
None => ()
}
match self.image_sampler {
Some(sampler) => sampler.release()
None => ()
}
match self.image_shader {
Some(shader) => shader.release()
None => ()
}
match self.white_bind_group {
Some(bind_group) => bind_group.release()
None => ()
}
match self.white_view {
Some(view) => view.release()
None => ()
}
match self.white_texture {
Some(texture) => {
texture.destroy()
texture.release()
}
None => ()
}
match self.advanced_vertex_buffer {
Some(buffer) => buffer.release()
None => ()
}
match self.advanced_pipeline_source_over {
Some(pipeline) => pipeline.release()
None => ()
}
match self.advanced_pipeline_multiply {
Some(pipeline) => pipeline.release()
None => ()
}
match self.advanced_pipeline_screen {
Some(pipeline) => pipeline.release()
None => ()
}
match self.advanced_pipeline_overlay {
Some(pipeline) => pipeline.release()
None => ()
}
match self.advanced_pipeline_darken {
Some(pipeline) => pipeline.release()
None => ()
}
match self.advanced_pipeline_lighten {
Some(pipeline) => pipeline.release()
None => ()
}
match self.advanced_pipeline_layout {
Some(layout) => layout.release()
None => ()
}
match self.advanced_overlay_pipeline_layout {
Some(layout) => layout.release()
None => ()
}
match self.advanced_bind_group_layout {
Some(layout) => layout.release()
None => ()
}
match self.advanced_overlay_bind_group_layout {
Some(layout) => layout.release()
None => ()
}
match self.advanced_sampler {
Some(sampler) => sampler.release()
None => ()
}
match self.advanced_shader {
Some(shader) => shader.release()
None => ()
}
match self.text_bind_group {
Some(bind_group) => bind_group.release()
None => ()
}
match self.text_pipeline {
Some(pipeline) => pipeline.release()
None => ()
}
match self.text_pipeline_layout {
Some(layout) => layout.release()
None => ()
}
match self.text_bind_group_layout {
Some(layout) => layout.release()
None => ()
}
match self.text_sampler {
Some(sampler) => sampler.release()
None => ()
}
match self.text_atlas_view {
Some(view) => view.release()
None => ()
}
match self.text_atlas_texture {
Some(texture) => texture.release()
None => ()
}
match self.text_shader {
Some(shader) => shader.release()
None => ()
}
match self.visual_pipeline {
Some(pipeline) => pipeline.release()
None => ()
}
match self.visual_shader {
Some(shader) => shader.release()
None => ()
}
match self.surface {
Some(surface) => {
if self.configured {
surface.unconfigure()
}
surface.release()
}
None => ()
}
match self.queue {
Some(queue) => queue.release()
None => ()
}
match self.device {
Some(device) => device.release()
None => ()
}
match self.adapter {
Some(adapter) => adapter.release()
None => ()
}
match self.instance {
Some(instance) => instance.release()
None => ()
}
self.visual_pipeline = None
self.visual_shader = None
self.surface = None
self.queue = None
self.device = None
self.adapter = None
self.instance = None
self.visual_vertex_buffer = None
self.text_vertex_buffer = None
self.image_vertex_buffer = None
self.image_pipeline = None
self.image_pipeline_layout = None
self.image_bind_group_layout = None
self.image_sampler = None
self.image_shader = None
self.advanced_shader = None
self.advanced_pipeline_source_over = None
self.advanced_pipeline_multiply = None
self.advanced_pipeline_screen = None
self.advanced_pipeline_overlay = None
self.advanced_pipeline_darken = None
self.advanced_pipeline_lighten = None
self.advanced_vertex_buffer = None
self.advanced_sampler = None
self.advanced_bind_group_layout = None
self.advanced_pipeline_layout = None
self.advanced_overlay_bind_group_layout = None
self.advanced_overlay_pipeline_layout = None
self.white_texture = None
self.white_view = None
self.white_bind_group = None
self.text_bind_group = None
self.text_pipeline = None
self.text_pipeline_layout = None
self.text_bind_group_layout = None
self.text_sampler = None
self.text_atlas_view = None
self.text_atlas_texture = None
self.text_shader = None
self.visual_vertices = []
self.text_vertices = []
self.image_vertices = []
self.draw_items = []
self.text_atlas_dirty = false
self.unsupported_command_count = 0
self.configured = false
}
///|
fn count_native_unsupported_commands(
commands : Array[@core.DrawCommand],
) -> Int {
@render_common.plan_renderer_command_fallbacks(commands).fallback_count()
}
///|
fn RendererHandle::render_wgpu(
self : RendererHandle,
commands : Array[@core.DrawCommand],
) -> Unit {
match (self.surface, self.device, self.queue, self.visual_pipeline) {
(Some(surface), Some(device), Some(queue), Some(visual_pipeline)) => {
let surface_texture = surface.get_current_texture()
if surface_texture.is_success() {
let texture = surface_texture.take_texture()
surface_texture.release()
let view = texture.create_view()
let clear = @render.first_clear_color(commands)
if self.text_atlas_dirty {
match self.text_atlas_texture {
Some(atlas_texture) => {
queue.write_texture_rgba8_2d(
atlas_texture,
self.glyph_atlas.width.reinterpret_as_uint(),
self.glyph_atlas.height.reinterpret_as_uint(),
self.glyph_atlas.to_bytes(),
)
self.text_atlas_dirty = false
self.glyph_atlas.dirty = false
}
None => ()
}
}
self.prepare_native_image_items(device, queue)
let root_plan = {
visual_vertices: self.visual_vertices,
text_vertices: self.text_vertices,
image_vertices: self.image_vertices,
items: self.draw_items,
atlas_dirty: self.text_atlas_dirty,
}
let encoder = device.create_command_encoder()
let frame_offscreens : Array[NativeOffscreenTexture] = []
let frame_backdrops : Array[NativeBackdropTexture] = []
let frame_buffers : Array[@wgpu_mbt.Buffer] = []
self.encode_plan_to_view(
encoder, device, queue, texture, view, visual_pipeline, root_plan, clear,
frame_offscreens, frame_backdrops, frame_buffers,
)
let command_buffer = encoder.finish()
queue.submit_one(command_buffer)
ignore(surface.present())
command_buffer.release()
release_frame_buffers(frame_buffers)
release_frame_backdrops(frame_backdrops)
release_frame_offscreens(frame_offscreens)
encoder.release()
view.release()
texture.release()
self.present_count += 1
} else {
surface_texture.release()
}
}
_ => ()
}
}
///|
fn RendererHandle::encode_plan_to_view(
self : RendererHandle,
encoder : @wgpu_mbt.CommandEncoder,
device : @wgpu_mbt.Device,
queue : @wgpu_mbt.Queue,
target_texture : @wgpu_mbt.Texture,
view : @wgpu_mbt.TextureView,
visual_pipeline : @wgpu_mbt.RenderPipeline,
plan : NativeDrawPlan,
clear : @core.Color,
frame_offscreens : Array[NativeOffscreenTexture],
frame_backdrops : Array[NativeBackdropTexture],
frame_buffers : Array[@wgpu_mbt.Buffer],
) -> Unit {
let buffers = upload_plan_gpu_buffers(device, queue, plan)
buffers.append_to_frame(frame_buffers)
let mut first_pass = true
let mut span_start = 0
let mut index = 0
while index < plan.items.length() {
match plan.items[index] {
NativeDrawItem::NativeLayer(layer) => {
if span_start < index {
self.draw_plan_item_span(
encoder,
view,
visual_pipeline,
device,
queue,
plan.items,
buffers,
start_index=span_start,
end_index=index,
clear~,
clear_pass=first_pass,
frame_buffers~,
)
first_pass = false
}
if self.draw_native_layer_to_view(
encoder,
target_texture,
view,
visual_pipeline,
device,
queue,
layer,
clear~,
clear_pass=first_pass,
frame_offscreens~,
frame_backdrops~,
frame_buffers~,
) {
first_pass = false
}
index += 1
span_start = index
}
_ => index += 1
}
}
if span_start < plan.items.length() {
self.draw_plan_item_span(
encoder,
view,
visual_pipeline,
device,
queue,
plan.items,
buffers,
start_index=span_start,
end_index=plan.items.length(),
clear~,
clear_pass=first_pass,
frame_buffers~,
)
first_pass = false
}
if first_pass {
clear_render_target(encoder, view, clear)
}
}
///|
fn RendererHandle::draw_plan_item_span(
self : RendererHandle,
encoder : @wgpu_mbt.CommandEncoder,
view : @wgpu_mbt.TextureView,
visual_pipeline : @wgpu_mbt.RenderPipeline,
device : @wgpu_mbt.Device,
queue : @wgpu_mbt.Queue,
items : Array[NativeDrawItem],
buffers : NativePlanGpuBuffers,
start_index~ : Int,
end_index~ : Int,
clear~ : @core.Color,
clear_pass~ : Bool,
frame_buffers~ : Array[@wgpu_mbt.Buffer],
) -> Unit {
let pass = if clear_pass {
encoder.begin_render_pass_color_clear(
view,
Float::from_double(clear.r),
Float::from_double(clear.g),
Float::from_double(clear.b),
Float::from_double(clear.a),
)
} else {
encoder.begin_render_pass_color_load(view)
}
self.apply_scissor(pass, None)
for index in start_index..
match buffers.visual_buffer {
Some(buffer) => {
self.apply_scissor(pass, scissor)
pass.set_pipeline(visual_pipeline)
pass.set_vertex_buffer(0U, buffer, 0UL, buffers.visual_size)
pass.draw(
count.reinterpret_as_uint(),
1U,
start.reinterpret_as_uint(),
0U,
)
}
None => ()
}
NativeDrawItem::NativeText(start, count, scissor) =>
match (self.text_pipeline, self.text_bind_group, buffers.text_buffer) {
(Some(text_pipeline), Some(text_bind_group), Some(buffer)) => {
self.apply_scissor(pass, scissor)
pass.set_pipeline(text_pipeline)
pass.set_bind_group0(text_bind_group)
pass.set_vertex_buffer(0U, buffer, 0UL, buffers.text_size)
pass.draw(
count.reinterpret_as_uint(),
1U,
start.reinterpret_as_uint(),
0U,
)
}
_ => ()
}
NativeDrawItem::NativeImage(start, count, scissor, run) =>
match
(
self.image_pipeline,
buffers.image_buffer,
self.image_cache.get(run.source),
) {
(Some(image_pipeline), Some(buffer), Some(resource)) => {
self.apply_scissor(pass, scissor)
pass.set_pipeline(image_pipeline)
pass.set_bind_group0(resource.bind_group)
pass.set_vertex_buffer(0U, buffer, 0UL, buffers.image_size)
pass.draw(
count.reinterpret_as_uint(),
1U,
start.reinterpret_as_uint(),
0U,
)
}
_ => ()
}
NativeDrawItem::NativeLayer(_) => ()
NativeDrawItem::NativeShaderEffect(effect) =>
self.draw_native_shader_effect(
pass, device, queue, effect, frame_buffers,
)
}
}
self.apply_scissor(pass, None)
pass.end()
pass.release()
}
///|
fn RendererHandle::draw_native_layer_to_view(
self : RendererHandle,
encoder : @wgpu_mbt.CommandEncoder,
target_texture : @wgpu_mbt.Texture,
view : @wgpu_mbt.TextureView,
visual_pipeline : @wgpu_mbt.RenderPipeline,
device : @wgpu_mbt.Device,
queue : @wgpu_mbt.Queue,
layer : NativeLayerRun,
clear~ : @core.Color,
clear_pass~ : Bool,
frame_offscreens~ : Array[NativeOffscreenTexture],
frame_backdrops~ : Array[NativeBackdropTexture],
frame_buffers~ : Array[@wgpu_mbt.Buffer],
) -> Bool {
guard self.create_offscreen_texture(device) is Some(offscreen) else {
return false
}
frame_offscreens.push(offscreen)
self.encode_plan_to_view(
encoder,
device,
queue,
offscreen.texture,
offscreen.view,
visual_pipeline,
layer.plan,
@core.Color::rgba(r=0.0, g=0.0, b=0.0, a=0.0),
frame_offscreens,
frame_backdrops,
frame_buffers,
)
if layer.blend_mode == @core.BlendMode::Overlay {
return self.draw_overlay_layer_to_view(
encoder,
target_texture,
view,
device,
queue,
layer,
offscreen.view,
clear~,
clear_pass~,
frame_backdrops~,
frame_buffers~,
)
}
let pass = if clear_pass {
encoder.begin_render_pass_color_clear(
view,
Float::from_double(clear.r),
Float::from_double(clear.g),
Float::from_double(clear.b),
Float::from_double(clear.a),
)
} else {
encoder.begin_render_pass_color_load(view)
}
let vertices = advanced_layer_vertices(self.size, layer)
self.draw_advanced_vertices(
pass,
device,
queue,
vertices,
offscreen.bind_group,
layer.blend_mode,
layer.scissor,
frame_buffers,
)
pass.end()
pass.release()
true
}
///|
fn RendererHandle::draw_native_shader_effect(
self : RendererHandle,
pass : @wgpu_mbt.RenderPass,
device : @wgpu_mbt.Device,
queue : @wgpu_mbt.Queue,
effect : NativeShaderEffectRun,
frame_buffers : Array[@wgpu_mbt.Buffer],
) -> Unit {
match self.white_bind_group {
Some(bind_group) => {
let colors = native_shader_effect_colors(effect)
let vertices = advanced_rect_vertices(
self.size,
effect.frame,
opacity=effect.opacity,
blend_mode=@core.BlendMode::SourceOver,
shader_kind=native_shader_kind(effect.name),
effect_amount=native_shader_effect_amount(effect),
filter=None,
color0=colors.0,
color1=colors.1,
transform=effect.transform,
)
self.draw_advanced_vertices(
pass,
device,
queue,
vertices,
bind_group,
@core.BlendMode::SourceOver,
effect.scissor,
frame_buffers,
)
}
None => ()
}
}
///|
fn RendererHandle::draw_overlay_layer_to_view(
self : RendererHandle,
encoder : @wgpu_mbt.CommandEncoder,
target_texture : @wgpu_mbt.Texture,
view : @wgpu_mbt.TextureView,
device : @wgpu_mbt.Device,
queue : @wgpu_mbt.Queue,
layer : NativeLayerRun,
layer_view : @wgpu_mbt.TextureView,
clear~ : @core.Color,
clear_pass~ : Bool,
frame_backdrops~ : Array[NativeBackdropTexture],
frame_buffers~ : Array[@wgpu_mbt.Buffer],
) -> Bool {
if clear_pass {
clear_render_target(encoder, view, clear)
}
guard self.create_backdrop_texture(device, target_texture, layer_view)
is Some(backdrop) else {
return false
}
encoder.copy_texture_to_texture_rgba8(
target_texture,
backdrop.texture,
@render.size_dim_to_uint(self.effective_physical_size().width),
@render.size_dim_to_uint(self.effective_physical_size().height),
)
let vertices = advanced_layer_vertices(self.size, layer)
let pass = encoder.begin_render_pass_color_load(view)
self.draw_advanced_overlay_vertices(
pass,
device,
queue,
vertices,
backdrop.bind_group,
layer.scissor,
frame_buffers,
)
pass.end()
pass.release()
frame_backdrops.push(backdrop)
true
}
///|
fn RendererHandle::draw_advanced_vertices(
self : RendererHandle,
pass : @wgpu_mbt.RenderPass,
device : @wgpu_mbt.Device,
queue : @wgpu_mbt.Queue,
vertices : Array[AdvancedVertex],
bind_group : @wgpu_mbt.BindGroup,
blend_mode : @core.BlendMode,
scissor : NativeScissor?,
frame_buffers : Array[@wgpu_mbt.Buffer],
) -> Unit {
if vertices.length() == 0 {
return
}
match self.advanced_pipeline_for_blend(blend_mode) {
Some(pipeline) => {
let bytes = advanced_vertices_to_bytes(vertices)
let required = bytes.length().to_uint64()
if required == 0UL {
return
}
let usage = @wgpu_mbt.BufferUsage::from_u64(
@wgpu_mbt.BUFFER_USAGE_VERTEX | @wgpu_mbt.BUFFER_USAGE_COPY_DST,
)
let buffer = device.create_buffer(
size=@render.grow_capacity(required),
usage~,
)
queue.write_buffer(buffer, 0UL, bytes)
frame_buffers.push(buffer)
self.apply_scissor(pass, scissor)
pass.set_pipeline(pipeline)
pass.set_bind_group0(bind_group)
pass.set_vertex_buffer(0U, buffer, 0UL, required)
pass.draw(vertices.length().reinterpret_as_uint(), 1U, 0U, 0U)
}
None => ()
}
}
///|
fn RendererHandle::draw_advanced_overlay_vertices(
self : RendererHandle,
pass : @wgpu_mbt.RenderPass,
device : @wgpu_mbt.Device,
queue : @wgpu_mbt.Queue,
vertices : Array[AdvancedVertex],
bind_group : @wgpu_mbt.BindGroup,
scissor : NativeScissor?,
frame_buffers : Array[@wgpu_mbt.Buffer],
) -> Unit {
if vertices.length() == 0 {
return
}
match self.advanced_pipeline_overlay {
Some(pipeline) => {
let bytes = advanced_vertices_to_bytes(vertices)
let required = bytes.length().to_uint64()
if required == 0UL {
return
}
let usage = @wgpu_mbt.BufferUsage::from_u64(
@wgpu_mbt.BUFFER_USAGE_VERTEX | @wgpu_mbt.BUFFER_USAGE_COPY_DST,
)
let buffer = device.create_buffer(
size=@render.grow_capacity(required),
usage~,
)
queue.write_buffer(buffer, 0UL, bytes)
frame_buffers.push(buffer)
self.apply_scissor(pass, scissor)
pass.set_pipeline(pipeline)
pass.set_bind_group0(bind_group)
pass.set_vertex_buffer(0U, buffer, 0UL, required)
pass.draw(vertices.length().reinterpret_as_uint(), 1U, 0U, 0U)
}
None => ()
}
}
///|
fn RendererHandle::advanced_pipeline_for_blend(
self : RendererHandle,
blend_mode : @core.BlendMode,
) -> @wgpu_mbt.RenderPipeline? {
match blend_mode {
@core.BlendMode::SourceOver => self.advanced_pipeline_source_over
@core.BlendMode::Multiply => self.advanced_pipeline_multiply
@core.BlendMode::Screen => self.advanced_pipeline_screen
@core.BlendMode::Overlay => self.advanced_pipeline_source_over
@core.BlendMode::Darken => self.advanced_pipeline_darken
@core.BlendMode::Lighten => self.advanced_pipeline_lighten
}
}
///|
fn RendererHandle::create_offscreen_texture(
self : RendererHandle,
device : @wgpu_mbt.Device,
) -> NativeOffscreenTexture? {
match (self.advanced_bind_group_layout, self.advanced_sampler) {
(Some(layout), Some(sampler)) => {
let size = self.effective_physical_size()
let usage = @wgpu_mbt.TextureUsage::from_u64(
@wgpu_mbt.TEXTURE_USAGE_RENDER_ATTACHMENT |
@wgpu_mbt.TEXTURE_USAGE_TEXTURE_BINDING |
@wgpu_mbt.TEXTURE_USAGE_COPY_SRC,
)
let texture = device.create_texture_u32(
@render.size_dim_to_uint(size.width),
@render.size_dim_to_uint(size.height),
1U,
usage,
@wgpu_mbt.TextureDimension::from_u32(@wgpu_mbt.TEXTURE_DIMENSION_2D),
self.surface_format,
)
let view = texture.create_view()
let bind_group = create_advanced_bind_group(
device, layout, sampler, view, view,
)
Some({ texture, view, bind_group })
}
_ => None
}
}
///|
fn RendererHandle::create_backdrop_texture(
self : RendererHandle,
device : @wgpu_mbt.Device,
target_texture : @wgpu_mbt.Texture,
layer_view : @wgpu_mbt.TextureView,
) -> NativeBackdropTexture? {
match (self.advanced_overlay_bind_group_layout, self.advanced_sampler) {
(Some(layout), Some(sampler)) => {
let width = @render.size_dim_to_uint(self.effective_physical_size().width)
let height = @render.size_dim_to_uint(
self.effective_physical_size().height,
)
let usage = @wgpu_mbt.TextureUsage::from_u64(
@wgpu_mbt.TEXTURE_USAGE_TEXTURE_BINDING |
@wgpu_mbt.TEXTURE_USAGE_COPY_DST,
)
let texture = device.create_texture_u32(
width,
height,
1U,
usage,
@wgpu_mbt.TextureDimension::from_u32(@wgpu_mbt.TEXTURE_DIMENSION_2D),
target_texture.format_u32(),
)
let view = texture.create_view()
let bind_group = create_advanced_bind_group(
device, layout, sampler, layer_view, view,
)
Some({ texture, view, bind_group })
}
_ => None
}
}
///|
fn NativeOffscreenTexture::release(self : NativeOffscreenTexture) -> Unit {
self.bind_group.release()
self.view.release()
self.texture.destroy()
self.texture.release()
}
///|
fn NativeBackdropTexture::release(self : NativeBackdropTexture) -> Unit {
self.bind_group.release()
self.view.release()
self.texture.destroy()
self.texture.release()
}
///|
fn upload_plan_gpu_buffers(
device : @wgpu_mbt.Device,
queue : @wgpu_mbt.Queue,
plan : NativeDrawPlan,
) -> NativePlanGpuBuffers {
let mut visual_buffer : @wgpu_mbt.Buffer? = None
let mut text_buffer : @wgpu_mbt.Buffer? = None
let mut image_buffer : @wgpu_mbt.Buffer? = None
let mut visual_size = 0UL
let mut text_size = 0UL
let mut image_size = 0UL
if plan.visual_vertices.length() > 0 {
let bytes = visual_vertices_to_bytes(plan.visual_vertices)
visual_size = bytes.length().to_uint64()
let usage = @wgpu_mbt.BufferUsage::from_u64(
@wgpu_mbt.BUFFER_USAGE_VERTEX | @wgpu_mbt.BUFFER_USAGE_COPY_DST,
)
let buffer = device.create_buffer(
size=@render.grow_capacity(visual_size),
usage~,
)
queue.write_buffer(buffer, 0UL, bytes)
visual_buffer = Some(buffer)
}
if plan.text_vertices.length() > 0 {
let bytes = text_vertices_to_bytes(plan.text_vertices)
text_size = bytes.length().to_uint64()
let usage = @wgpu_mbt.BufferUsage::from_u64(
@wgpu_mbt.BUFFER_USAGE_VERTEX | @wgpu_mbt.BUFFER_USAGE_COPY_DST,
)
let buffer = device.create_buffer(
size=@render.grow_capacity(text_size),
usage~,
)
queue.write_buffer(buffer, 0UL, bytes)
text_buffer = Some(buffer)
}
if plan.image_vertices.length() > 0 {
let bytes = image_vertices_to_bytes(plan.image_vertices)
image_size = bytes.length().to_uint64()
let usage = @wgpu_mbt.BufferUsage::from_u64(
@wgpu_mbt.BUFFER_USAGE_VERTEX | @wgpu_mbt.BUFFER_USAGE_COPY_DST,
)
let buffer = device.create_buffer(
size=@render.grow_capacity(image_size),
usage~,
)
queue.write_buffer(buffer, 0UL, bytes)
image_buffer = Some(buffer)
}
{
visual_buffer,
text_buffer,
image_buffer,
visual_size,
text_size,
image_size,
}
}
///|
fn NativePlanGpuBuffers::append_to_frame(
self : NativePlanGpuBuffers,
frame_buffers : Array[@wgpu_mbt.Buffer],
) -> Unit {
match self.visual_buffer {
Some(buffer) => frame_buffers.push(buffer)
None => ()
}
match self.text_buffer {
Some(buffer) => frame_buffers.push(buffer)
None => ()
}
match self.image_buffer {
Some(buffer) => frame_buffers.push(buffer)
None => ()
}
}
///|
fn release_frame_buffers(frame_buffers : Array[@wgpu_mbt.Buffer]) -> Unit {
for buffer in frame_buffers {
buffer.release()
}
frame_buffers.clear()
}
///|
fn release_frame_backdrops(
frame_backdrops : Array[NativeBackdropTexture],
) -> Unit {
for backdrop in frame_backdrops {
backdrop.release()
}
frame_backdrops.clear()
}
///|
fn release_frame_offscreens(
frame_offscreens : Array[NativeOffscreenTexture],
) -> Unit {
for offscreen in frame_offscreens {
offscreen.release()
}
frame_offscreens.clear()
}
///|
fn clear_render_target(
encoder : @wgpu_mbt.CommandEncoder,
view : @wgpu_mbt.TextureView,
clear : @core.Color,
) -> Unit {
let pass = encoder.begin_render_pass_color_clear(
view,
Float::from_double(clear.r),
Float::from_double(clear.g),
Float::from_double(clear.b),
Float::from_double(clear.a),
)
pass.end()
pass.release()
}
///|
fn RendererHandle::apply_scissor(
self : RendererHandle,
pass : @wgpu_mbt.RenderPass,
scissor : NativeScissor?,
) -> Unit {
match scissor {
Some(scissor) => {
let width = max_native_int(0, scissor.width)
let height = max_native_int(0, scissor.height)
pass.set_scissor_rect(
max_native_int(0, scissor.x).reinterpret_as_uint(),
max_native_int(0, scissor.y).reinterpret_as_uint(),
width.reinterpret_as_uint(),
height.reinterpret_as_uint(),
)
}
None =>
pass.set_scissor_rect(
0U,
0U,
@render.size_dim_to_uint(self.effective_physical_size().width),
@render.size_dim_to_uint(self.effective_physical_size().height),
)
}
}
///|
fn max_native_int(a : Int, b : Int) -> Int {
if a > b {
a
} else {
b
}
}
///|
fn create_visual_pipeline(
device : @wgpu_mbt.Device,
shader : @wgpu_mbt.ShaderModule,
format : @wgpu_mbt.TextureFormat,
) -> @wgpu_mbt.RenderPipeline {
let builder = try! @wgpu_mbt.RenderPipelineDescBuilder::new(shader)
try! builder.set_color_target_format(format)
try! builder.enable_alpha_blend()
try! builder.set_vertex_buffer_layout(
visual_vertex_stride,
@wgpu_mbt.VERTEX_STEP_MODE_VERTEX,
)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X2, 0UL, 0U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X2, 8UL, 1U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 16UL, 2U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 32UL, 3U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X2, 48UL, 4U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 56UL, 5U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 72UL, 6U)
try! builder.create_pipeline(device)
}
///|
fn create_image_pipeline(
device : @wgpu_mbt.Device,
shader : @wgpu_mbt.ShaderModule,
format : @wgpu_mbt.TextureFormat,
layout : @wgpu_mbt.PipelineLayout,
) -> @wgpu_mbt.RenderPipeline {
let builder = try! @wgpu_mbt.RenderPipelineDescBuilder::new(shader, layout~)
try! builder.set_color_target_format(format)
try! builder.enable_alpha_blend()
try! builder.set_vertex_buffer_layout(
image_vertex_stride,
@wgpu_mbt.VERTEX_STEP_MODE_VERTEX,
)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X2, 0UL, 0U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X2, 8UL, 1U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32, 16UL, 2U)
try! builder.create_pipeline(device)
}
///|
fn create_text_pipeline(
device : @wgpu_mbt.Device,
shader : @wgpu_mbt.ShaderModule,
format : @wgpu_mbt.TextureFormat,
layout : @wgpu_mbt.PipelineLayout,
) -> @wgpu_mbt.RenderPipeline {
let builder = try! @wgpu_mbt.RenderPipelineDescBuilder::new(shader, layout~)
try! builder.set_color_target_format(format)
try! builder.enable_alpha_blend()
try! builder.set_vertex_buffer_layout(
text_vertex_stride,
@wgpu_mbt.VERTEX_STEP_MODE_VERTEX,
)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X2, 0UL, 0U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X2, 8UL, 1U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 16UL, 2U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32, 32UL, 3U)
try! builder.create_pipeline(device)
}
///|
fn create_advanced_pipeline(
device : @wgpu_mbt.Device,
shader : @wgpu_mbt.ShaderModule,
format : @wgpu_mbt.TextureFormat,
layout : @wgpu_mbt.PipelineLayout,
blend_mode : @core.BlendMode,
) -> @wgpu_mbt.RenderPipeline {
let builder = try! @wgpu_mbt.RenderPipelineDescBuilder::new(shader, layout~)
try! builder.set_color_target_format(format)
set_advanced_blend(builder, blend_mode)
try! builder.set_vertex_buffer_layout(
advanced_vertex_stride,
@wgpu_mbt.VERTEX_STEP_MODE_VERTEX,
)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X2, 0UL, 0U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X2, 8UL, 1U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 16UL, 2U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 32UL, 3U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 48UL, 4U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 64UL, 5U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 80UL, 6U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 96UL, 7U)
try! builder.add_vertex_attribute(
@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4,
112UL,
8U,
)
try! builder.add_vertex_attribute(
@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4,
128UL,
9U,
)
try! builder.add_vertex_attribute(
@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4,
144UL,
10U,
)
try! builder.add_vertex_attribute(
@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4,
160UL,
11U,
)
try! builder.create_pipeline(device)
}
///|
fn create_advanced_overlay_bind_group_layout(
device : @wgpu_mbt.Device,
) -> @wgpu_mbt.BindGroupLayout {
let builder = @wgpu_mbt.BindGroupLayoutBuilder::new(max_entries=3UL)
let stage = @wgpu_mbt.ShaderStage::from_u64(@wgpu_mbt.SHADER_STAGE_FRAGMENT)
ignore(
builder.add_sampler(0U, stage, @wgpu_mbt.SAMPLER_BINDING_TYPE_FILTERING),
)
ignore(
builder.add_texture(
1U,
stage,
@wgpu_mbt.TEXTURE_SAMPLE_TYPE_FLOAT,
@wgpu_mbt.TEXTURE_VIEW_DIMENSION_2D,
),
)
ignore(
builder.add_texture(
2U,
stage,
@wgpu_mbt.TEXTURE_SAMPLE_TYPE_FLOAT,
@wgpu_mbt.TEXTURE_VIEW_DIMENSION_2D,
),
)
builder.finish(device)
}
///|
fn create_advanced_bind_group(
device : @wgpu_mbt.Device,
layout : @wgpu_mbt.BindGroupLayout,
sampler : @wgpu_mbt.Sampler,
layer_view : @wgpu_mbt.TextureView,
backdrop_view : @wgpu_mbt.TextureView,
) -> @wgpu_mbt.BindGroup {
let builder = @wgpu_mbt.BindGroupBuilder::new(max_entries=3UL)
ignore(builder.add_sampler(0U, sampler))
ignore(builder.add_texture_view(1U, layer_view))
ignore(builder.add_texture_view(2U, backdrop_view))
builder.finish(device, layout)
}
///|
fn create_advanced_overlay_pipeline(
device : @wgpu_mbt.Device,
shader : @wgpu_mbt.ShaderModule,
format : @wgpu_mbt.TextureFormat,
layout : @wgpu_mbt.PipelineLayout,
) -> @wgpu_mbt.RenderPipeline {
let builder = try! @wgpu_mbt.RenderPipelineDescBuilder::new(shader, layout~)
try! builder.set_color_target_format(format)
try! builder.disable_blend()
try! builder.set_vertex_buffer_layout(
advanced_vertex_stride,
@wgpu_mbt.VERTEX_STEP_MODE_VERTEX,
)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X2, 0UL, 0U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X2, 8UL, 1U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 16UL, 2U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 32UL, 3U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 48UL, 4U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 64UL, 5U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 80UL, 6U)
try! builder.add_vertex_attribute(@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4, 96UL, 7U)
try! builder.add_vertex_attribute(
@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4,
112UL,
8U,
)
try! builder.add_vertex_attribute(
@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4,
128UL,
9U,
)
try! builder.add_vertex_attribute(
@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4,
144UL,
10U,
)
try! builder.add_vertex_attribute(
@wgpu_mbt.VERTEX_FORMAT_FLOAT32X4,
160UL,
11U,
)
try! builder.create_pipeline(device)
}
///|
fn set_advanced_blend(
builder : @wgpu_mbt.RenderPipelineDescBuilder,
blend_mode : @core.BlendMode,
) -> Unit {
match blend_mode {
@core.BlendMode::SourceOver | @core.BlendMode::Overlay =>
try! builder.enable_alpha_blend()
@core.BlendMode::Multiply =>
try! builder.set_blend_components(
@wgpu_mbt.BLEND_FACTOR_DST,
@wgpu_mbt.BLEND_FACTOR_ZERO,
@wgpu_mbt.BLEND_OPERATION_ADD,
@wgpu_mbt.BLEND_FACTOR_ONE,
@wgpu_mbt.BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
@wgpu_mbt.BLEND_OPERATION_ADD,
)
@core.BlendMode::Screen =>
try! builder.set_blend_components(
@wgpu_mbt.BLEND_FACTOR_ONE,
@wgpu_mbt.BLEND_FACTOR_ONE_MINUS_SRC,
@wgpu_mbt.BLEND_OPERATION_ADD,
@wgpu_mbt.BLEND_FACTOR_ONE,
@wgpu_mbt.BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
@wgpu_mbt.BLEND_OPERATION_ADD,
)
@core.BlendMode::Darken =>
try! builder.set_blend_components(
@wgpu_mbt.BLEND_FACTOR_ONE,
@wgpu_mbt.BLEND_FACTOR_ONE,
@wgpu_mbt.BLEND_OPERATION_MIN,
@wgpu_mbt.BLEND_FACTOR_ONE,
@wgpu_mbt.BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
@wgpu_mbt.BLEND_OPERATION_ADD,
)
@core.BlendMode::Lighten =>
try! builder.set_blend_components(
@wgpu_mbt.BLEND_FACTOR_ONE,
@wgpu_mbt.BLEND_FACTOR_ONE,
@wgpu_mbt.BLEND_OPERATION_MAX,
@wgpu_mbt.BLEND_FACTOR_ONE,
@wgpu_mbt.BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
@wgpu_mbt.BLEND_OPERATION_ADD,
)
}
}