metal: handle HiDPI scaling

This commit is contained in:
Mitchell Hashimoto
2022-10-30 11:04:15 -07:00
parent fb49595904
commit 0058906035
3 changed files with 27 additions and 13 deletions

View File

@ -1,4 +1,11 @@
//! Renderer implementation for Metal.
//!
//! Open questions:
//!
//! - This requires a "px_scale" uniform to account for pixel scaling
//! issues with Retina. I'm not 100% sure why this is necessary and why
//! this doesn't happen with OpenGL.
//!
pub const Metal = @This();
const std = @import("std");
@ -64,7 +71,16 @@ const GPUCell = extern struct {
};
const GPUUniforms = extern struct {
/// The projection matrix for turning world coordinates to normalized.
/// This is calculated based on the size of the screen.
projection_matrix: math.Mat,
/// A scale factor to apply to all pixels given as input (including
/// in this uniform i.e. cell_size). This is due to HiDPI screens (Retina)
/// mismatch with the window.
px_scale: [2]f32,
/// Size of a single cell in pixels, unscaled.
cell_size: [2]f32,
};
@ -292,11 +308,8 @@ pub fn render(
@floatCast(f32, bounds.size.height),
0,
),
.cell_size = .{
self.cell_size.width * scaleX,
self.cell_size.height * scaleY,
},
.px_scale = .{ scaleX, scaleY },
.cell_size = .{ self.cell_size.width, self.cell_size.height },
};
}

View File

@ -8,6 +8,7 @@ enum Mode : uint8_t {
struct Uniforms {
float4x4 projection_matrix;
float2 px_scale;
float2 cell_size;
};
@ -45,8 +46,11 @@ vertex VertexOut uber_vertex(
VertexIn input [[ stage_in ]],
constant Uniforms &uniforms [[ buffer(1) ]]
) {
// TODO: scale with cell width
float2 cell_size = uniforms.cell_size * uniforms.px_scale;
// Convert the grid x,y into world space x, y by accounting for cell size
float2 cell_pos = uniforms.cell_size * input.grid_pos;
float2 cell_pos = cell_size * input.grid_pos;
// Turn the cell position into a vertex point depending on the
// vertex ID. Since we use instanced drawing, we have 4 vertices
@ -62,9 +66,6 @@ vertex VertexOut uber_vertex(
position.x = (vid == 0 || vid == 1) ? 1.0f : 0.0f;
position.y = (vid == 0 || vid == 3) ? 0.0f : 1.0f;
// TODO: scale
float2 cell_size = uniforms.cell_size;
VertexOut out;
out.mode = input.mode;
out.color = float4(input.color) / 255.0f;
@ -73,14 +74,14 @@ vertex VertexOut uber_vertex(
// Calculate the final position of our cell in world space.
// We have to add our cell size since our vertices are offset
// one cell up and to the left. (Do the math to verify yourself)
cell_pos = cell_pos + uniforms.cell_size * position;
cell_pos = cell_pos + cell_size * position;
out.position = uniforms.projection_matrix * float4(cell_pos.x, cell_pos.y, 0.0f, 1.0f);
break;
case MODE_FG:
float2 glyph_size = float2(input.glyph_size);
float2 glyph_offset = float2(input.glyph_offset);
float2 glyph_size = float2(input.glyph_size) * uniforms.px_scale;
float2 glyph_offset = float2(input.glyph_offset) * uniforms.px_scale;
// TODO: downsampling

View File

@ -147,7 +147,7 @@ void main() {
glyph_offset_calc.y = cell_size_scaled.y - glyph_offset_calc.y;
// Calculate the final position of the cell.
cell_pos = cell_pos + glyph_size_downsampled * position + glyph_offset_calc;
cell_pos = cell_pos + (glyph_size_downsampled * position) + glyph_offset_calc;
gl_Position = projection * vec4(cell_pos, cell_z, 1.0);
// We need to convert our texture position and size to normalized