gpu rasterization works now

Kate created

Change summary

crates/gpui/src/platform/windows/color_text_raster.hlsl |  33 +
crates/gpui/src/platform/windows/direct_write.rs        | 213 +++++++---
2 files changed, 175 insertions(+), 71 deletions(-)

Detailed changes

crates/gpui/src/platform/windows/color_text_raster.hlsl 🔗

@@ -1,22 +1,39 @@
-
-struct RasterVertexInput {
-    float2 position : POSITION;
-};
-
 struct RasterVertexOutput {
     float4 position : SV_Position;
+    float2 texcoord : TEXCOORD0;
 };
 
-RasterVertexOutput vertex(RasterVertexInput input) {
+RasterVertexOutput vertex(uint vertexID : SV_VERTEXID)
+{
     RasterVertexOutput output;
-    output.position = float4(input.position, 0.0, 1.0);
+    output.texcoord = float2((vertexID << 1) & 2, vertexID & 2);
+    output.position = float4(output.texcoord * 2.0f - 1.0f, 0.0f, 1.0f);
+    output.position.y = -output.position.y;
+
     return output;
 }
 
 struct PixelInput {
     float4 position: SV_Position;
+    float2 texcoord : TEXCOORD0;
+};
+
+struct Bounds {
+    int2 origin;
+    int2 size;
+};
+
+Texture2D<float4> t_layer : register(t0);
+SamplerState s_layer : register(s0);
+
+cbuffer GlyphLayerTextureParams : register(b0) {
+    Bounds bounds;
+    float4 run_color;
 };
 
 float4 pixel(PixelInput input): SV_Target {
-    return float4(input.position.xy, 0.0, 1.0);
+    float3 sampled = t_layer.Sample(s_layer, input.texcoord.xy).rgb;
+    float alpha = (sampled.r + sampled.g + sampled.b) / 3;
+
+    return float4(run_color.rgb, alpha);
 }

crates/gpui/src/platform/windows/direct_write.rs 🔗

@@ -10,16 +10,8 @@ use windows::{
         Foundation::*,
         Globalization::GetUserDefaultLocaleName,
         Graphics::{
-            Direct3D11::{
-                D3D11_BIND_SHADER_RESOURCE, D3D11_BUFFER_DESC, D3D11_CPU_ACCESS_WRITE,
-                D3D11_MAP_WRITE_DISCARD, D3D11_RESOURCE_MISC_BUFFER_STRUCTURED,
-                D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, D3D11_USAGE_DYNAMIC, ID3D11Device,
-                ID3D11DeviceContext, ID3D11ShaderResourceView, ID3D11Texture2D,
-            },
-            DirectWrite::*,
-            Dxgi::Common::*,
-            Gdi::LOGFONTW,
-            Imaging::*,
+            Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, Direct3D11::*, DirectWrite::*,
+            Dxgi::Common::*, Gdi::LOGFONTW, Imaging::*,
         },
         System::SystemServices::LOCALE_NAME_MAX_LENGTH,
         UI::WindowsAndMessaging::*,
@@ -847,8 +839,8 @@ impl DirectWriteState {
                 measuring_mode,
                 &transform,
                 point(baseline_origin_x, baseline_origin_y),
-                size(DevicePixels(0), DevicePixels(0)),
-                size(0, 0),
+                bitmap_size,
+                size(texture_width, texture_height),
             );
             // // todo: support more glyph image formats for more exotic fonts, for now it should fallback to monochrome rendering
             // let color_enumerator = unsafe {
@@ -1175,24 +1167,14 @@ impl DirectWriteState {
             }
         }
 
-        let params = glyph_layers
-            .iter()
-            .enumerate()
-            .map(|(index, e)| GlyphLayerTextureParams {
-                run_color: e.run_color,
-                bounds: e.bounds,
-                alpha_texture_index: index as u32,
-            })
-            .collect::<Vec<_>>();
-
         let params_buffer = {
             let desc = D3D11_BUFFER_DESC {
-                ByteWidth: (std::mem::size_of::<GlyphLayerTextureParams>() * params.len()) as u32,
+                ByteWidth: std::mem::size_of::<GlyphLayerTextureParams>() as u32,
                 Usage: D3D11_USAGE_DYNAMIC,
-                BindFlags: D3D11_BIND_SHADER_RESOURCE.0 as u32,
+                BindFlags: D3D11_BIND_CONSTANT_BUFFER.0 as u32,
                 CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32,
-                MiscFlags: D3D11_RESOURCE_MISC_BUFFER_STRUCTURED.0 as u32,
-                StructureByteStride: std::mem::size_of::<GlyphLayerTextureParams>() as u32,
+                MiscFlags: 0,
+                StructureByteStride: 0,
             };
 
             let mut buffer = None;
@@ -1201,38 +1183,9 @@ impl DirectWriteState {
                     .device
                     .CreateBuffer(&desc, None, Some(&mut buffer))
             }?;
-            buffer.unwrap()
-        };
-        let params_buffer_view = {
-            let mut view = None;
-            unsafe {
-                self.gpu_state.device.CreateShaderResourceView(
-                    &params_buffer,
-                    None,
-                    Some(&mut view),
-                )
-            }?;
-            [view]
-        };
-
-        unsafe {
-            let mut dest = std::mem::zeroed();
-            self.gpu_state.device_context.Map(
-                &params_buffer,
-                0,
-                D3D11_MAP_WRITE_DISCARD,
-                0,
-                Some(&mut dest),
-            )?;
-            std::ptr::copy_nonoverlapping(params.as_ptr(), dest.pData as *mut _, params.len());
-            self.gpu_state.device_context.Unmap(&params_buffer, 0);
+            [buffer]
         };
 
-        let textures = glyph_layers
-            .iter()
-            .map(|layer| Some(layer.texture_view.clone()))
-            .collect::<Vec<_>>();
-
         let vertex_shader = {
             let source =
                 shader_resources::build_shader_blob("color_text_raster", "vertex", "vs_5_0")?;
@@ -1251,6 +1204,105 @@ impl DirectWriteState {
             shader.unwrap()
         };
 
+        let render_target_texture = {
+            let mut texture = None;
+            let desc = D3D11_TEXTURE2D_DESC {
+                Width: bitmap_size.width.0 as u32,
+                Height: bitmap_size.height.0 as u32,
+                MipLevels: 1,
+                ArraySize: 1,
+                Format: DXGI_FORMAT_B8G8R8A8_UNORM,
+                SampleDesc: DXGI_SAMPLE_DESC {
+                    Count: 1,
+                    Quality: 0,
+                },
+                Usage: D3D11_USAGE_DEFAULT,
+                BindFlags: D3D11_BIND_RENDER_TARGET.0 as u32,
+                CPUAccessFlags: D3D11_CPU_ACCESS_READ.0 as u32,
+                MiscFlags: 0,
+            };
+            unsafe {
+                self.gpu_state
+                    .device
+                    .CreateTexture2D(&desc, None, Some(&mut texture))
+            }?;
+            texture.unwrap()
+        };
+
+        let render_target_view = {
+            let desc = D3D11_RENDER_TARGET_VIEW_DESC {
+                Format: DXGI_FORMAT_B8G8R8A8_UNORM,
+                ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2D,
+                Anonymous: D3D11_RENDER_TARGET_VIEW_DESC_0 {
+                    Texture2D: D3D11_TEX2D_RTV { MipSlice: 0 },
+                },
+            };
+            let mut rtv = None;
+            unsafe {
+                self.gpu_state.device.CreateRenderTargetView(
+                    &render_target_texture,
+                    Some(&desc),
+                    Some(&mut rtv),
+                )
+            }?;
+            [rtv]
+        };
+
+        let blend_state = {
+            let mut blend_state = None;
+            let desc = D3D11_BLEND_DESC {
+                AlphaToCoverageEnable: false.into(),
+                IndependentBlendEnable: false.into(),
+                RenderTarget: [
+                    D3D11_RENDER_TARGET_BLEND_DESC {
+                        BlendEnable: true.into(),
+                        SrcBlend: D3D11_BLEND_SRC_ALPHA,
+                        DestBlend: D3D11_BLEND_INV_SRC_ALPHA,
+                        BlendOp: D3D11_BLEND_OP_ADD,
+                        SrcBlendAlpha: D3D11_BLEND_ONE,
+                        DestBlendAlpha: D3D11_BLEND_INV_SRC_ALPHA,
+                        BlendOpAlpha: D3D11_BLEND_OP_ADD,
+                        RenderTargetWriteMask: D3D11_COLOR_WRITE_ENABLE_ALL.0 as u8,
+                    },
+                    Default::default(),
+                    Default::default(),
+                    Default::default(),
+                    Default::default(),
+                    Default::default(),
+                    Default::default(),
+                    Default::default(),
+                ],
+            };
+            unsafe {
+                self.gpu_state
+                    .device
+                    .CreateBlendState(&desc, Some(&mut blend_state))
+            }?;
+            blend_state.unwrap()
+        };
+
+        let sampler = {
+            let mut sampler = None;
+            let desc = D3D11_SAMPLER_DESC {
+                Filter: D3D11_FILTER_MIN_MAG_MIP_POINT,
+                AddressU: D3D11_TEXTURE_ADDRESS_BORDER,
+                AddressV: D3D11_TEXTURE_ADDRESS_BORDER,
+                AddressW: D3D11_TEXTURE_ADDRESS_BORDER,
+                MipLODBias: 0.0,
+                MaxAnisotropy: 1,
+                ComparisonFunc: D3D11_COMPARISON_ALWAYS,
+                BorderColor: [0.0, 0.0, 0.0, 0.0],
+                MinLOD: 0.0,
+                MaxLOD: 0.0,
+            };
+            unsafe {
+                self.gpu_state
+                    .device
+                    .CreateSamplerState(&desc, Some(&mut sampler))
+            }?;
+            [sampler]
+        };
+
         let pixel_shader = {
             let source =
                 shader_resources::build_shader_blob("color_text_raster", "pixel", "ps_5_0")?;
@@ -1276,14 +1328,50 @@ impl DirectWriteState {
             .start_frame_capture(std::ptr::null(), std::ptr::null());
 
         let device_context = &self.gpu_state.device_context;
-        unsafe { device_context.VSSetShaderResources(0, Some(textures.as_slice())) };
-        unsafe { device_context.PSSetShaderResources(0, Some(textures.as_slice())) };
-        unsafe { device_context.VSSetShaderResources(1, Some(&params_buffer_view)) };
-        unsafe { device_context.PSSetShaderResources(1, Some(&params_buffer_view)) };
+        unsafe { device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP) };
         unsafe { device_context.VSSetShader(&vertex_shader, None) };
         unsafe { device_context.PSSetShader(&pixel_shader, None) };
+        unsafe { device_context.VSSetConstantBuffers(0, Some(&params_buffer)) };
+        unsafe { device_context.PSSetConstantBuffers(0, Some(&params_buffer)) };
+        unsafe { device_context.OMSetRenderTargets(Some(&render_target_view), None) };
+        unsafe { device_context.PSSetSamplers(0, Some(&sampler)) };
+        unsafe { device_context.OMSetBlendState(&blend_state, None, 0xffffffff) };
+
+        for layer in glyph_layers {
+            let params = GlyphLayerTextureParams {
+                run_color: layer.run_color,
+                bounds: layer.bounds,
+            };
+            unsafe {
+                let mut dest = std::mem::zeroed();
+                self.gpu_state.device_context.Map(
+                    params_buffer[0].as_ref().unwrap(),
+                    0,
+                    D3D11_MAP_WRITE_DISCARD,
+                    0,
+                    Some(&mut dest),
+                )?;
+                std::ptr::copy_nonoverlapping(&params as *const _, dest.pData as *mut _, 1);
+                self.gpu_state
+                    .device_context
+                    .Unmap(params_buffer[0].as_ref().unwrap(), 0);
+            };
 
-        unsafe { device_context.DrawInstanced(4, params.len() as u32, 0, 0) };
+            let texture = [Some(layer.texture_view)];
+            unsafe { device_context.PSSetShaderResources(0, Some(&texture)) };
+
+            let viewport = [D3D11_VIEWPORT {
+                TopLeftX: layer.bounds.origin.x as f32,
+                TopLeftY: layer.bounds.origin.y as f32,
+                Width: layer.bounds.size.width as f32,
+                Height: layer.bounds.size.height as f32,
+                MinDepth: 0.0,
+                MaxDepth: 1.0,
+            }];
+            unsafe { device_context.RSSetViewports(Some(&viewport)) };
+
+            unsafe { device_context.Draw(4, 0) };
+        }
 
         #[cfg(feature = "enable-renderdoc")]
         self.renderdoc
@@ -1440,9 +1528,8 @@ impl GlyphLayerTexture {
 
 #[repr(C)]
 struct GlyphLayerTextureParams {
-    run_color: Rgba,
     bounds: Bounds<i32>,
-    alpha_texture_index: u32,
+    run_color: Rgba,
 }
 
 struct TextRendererWrapper(pub IDWriteTextRenderer);