Skip to content

Commit 2fbf8f5

Browse files
author
osy
committed
CocoaSpice: moved screen translation to shaders
Previously, we were using viewports to handle translation and scaling. This led to issues where if the VM display is larger than the device's display then the screen would be cut off. We move the affine transformation to part of the vertex shader now. Fixes #181
1 parent 86bac46 commit 2fbf8f5

File tree

3 files changed

+55
-25
lines changed

3 files changed

+55
-25
lines changed

Renderer/UTMRenderer.m

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,39 @@ - (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
102102
_viewportSize.y = size.height;
103103
}
104104

105+
/// Create a translation+scale matrix
106+
static matrix_float4x4 matrix_scale_translate(CGFloat scale, CGPoint translate)
107+
{
108+
matrix_float4x4 m = {
109+
.columns[0] = {
110+
scale,
111+
0,
112+
0,
113+
0
114+
},
115+
.columns[1] = {
116+
0,
117+
scale,
118+
0,
119+
0
120+
},
121+
.columns[2] = {
122+
0,
123+
0,
124+
1,
125+
0
126+
},
127+
.columns[3] = {
128+
translate.x,
129+
-translate.y, // y flipped
130+
0,
131+
1
132+
}
133+
134+
};
135+
return m;
136+
}
137+
105138
/// Called whenever the view needs to render a frame
106139
- (void)drawInMTKView:(nonnull MTKView *)view
107140
{
@@ -133,18 +166,9 @@ - (void)drawInMTKView:(nonnull MTKView *)view
133166
dispatch_semaphore_wait(screenLock, DISPATCH_TIME_FOREVER);
134167

135168
// Render the screen first
136-
// Set the region of the drawable to which we'll draw.
137-
CGSize scaled = CGSizeMake(_viewportSize.x * self.sourceScreen.viewportScale,
138-
_viewportSize.y * self.sourceScreen.viewportScale);
139-
MTLViewport viewport = {
140-
self.sourceScreen.viewportOrigin.x + -scaled.width /2 + _viewportSize.x/2,
141-
self.sourceScreen.viewportOrigin.y + -scaled.height/2 + _viewportSize.y/2,
142-
scaled.width,
143-
scaled.height,
144-
-1.0,
145-
1.0
146-
};
147-
[renderEncoder setViewport:viewport];
169+
170+
matrix_float4x4 transform = matrix_scale_translate(self.sourceScreen.viewportScale,
171+
self.sourceScreen.viewportOrigin);
148172

149173
[renderEncoder setRenderPipelineState:_pipelineState];
150174

@@ -156,6 +180,10 @@ - (void)drawInMTKView:(nonnull MTKView *)view
156180
length:sizeof(_viewportSize)
157181
atIndex:UTMVertexInputIndexViewportSize];
158182

183+
[renderEncoder setVertexBytes:&transform
184+
length:sizeof(transform)
185+
atIndex:UTMVertexInputIndexTransform];
186+
159187
[renderEncoder setVertexBytes:&hasAlpha
160188
length:sizeof(hasAlpha)
161189
atIndex:UTMVertexInputIndexHasAlpha];
@@ -179,23 +207,20 @@ - (void)drawInMTKView:(nonnull MTKView *)view
179207
dispatch_semaphore_wait(cursorLock, DISPATCH_TIME_FOREVER);
180208

181209
// Next render the cursor
182-
CGSize scaled = CGSizeMake(_viewportSize.x * self.sourceCursor.viewportScale,
183-
_viewportSize.y * self.sourceCursor.viewportScale);
184-
MTLViewport cursorViewport = {
185-
self.sourceCursor.viewportOrigin.x + self.sourceScreen.viewportOrigin.x + -scaled.width /2 + _viewportSize.x/2,
186-
self.sourceCursor.viewportOrigin.y + self.sourceScreen.viewportOrigin.y + -scaled.height/2 + _viewportSize.y/2,
187-
scaled.width,
188-
scaled.height,
189-
-1.0,
190-
1.0
191-
};
192-
[renderEncoder setViewport:cursorViewport];
210+
matrix_float4x4 transform = matrix_scale_translate(self.sourceScreen.viewportScale,
211+
CGPointMake(self.sourceScreen.viewportOrigin.x +
212+
self.sourceCursor.viewportOrigin.x,
213+
self.sourceScreen.viewportOrigin.y +
214+
self.sourceCursor.viewportOrigin.y));
193215
[renderEncoder setVertexBuffer:self.sourceCursor.vertices
194216
offset:0
195217
atIndex:UTMVertexInputIndexVertices];
196218
[renderEncoder setVertexBytes:&_viewportSize
197219
length:sizeof(_viewportSize)
198220
atIndex:UTMVertexInputIndexViewportSize];
221+
[renderEncoder setVertexBytes:&transform
222+
length:sizeof(transform)
223+
atIndex:UTMVertexInputIndexTransform];
199224
[renderEncoder setVertexBytes:&hasAlpha
200225
length:sizeof(hasAlpha)
201226
atIndex:UTMVertexInputIndexHasAlpha];

Renderer/UTMShaderTypes.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ typedef enum UTMVertexInputIndex
1616
{
1717
UTMVertexInputIndexVertices = 0,
1818
UTMVertexInputIndexViewportSize = 1,
19-
UTMVertexInputIndexHasAlpha = 2,
19+
UTMVertexInputIndexTransform = 2,
20+
UTMVertexInputIndexHasAlpha = 3,
2021
} UTMVertexInputIndex;
2122

2223
// Texture index values shared between shader and C code to ensure Metal shader buffer inputs match

Renderer/UTMShaders.metal

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,20 @@ vertex RasterizerData
3535
vertexShader(uint vertexID [[ vertex_id ]],
3636
constant UTMVertex *vertexArray [[ buffer(UTMVertexInputIndexVertices) ]],
3737
constant vector_uint2 *viewportSizePointer [[ buffer(UTMVertexInputIndexViewportSize) ]],
38+
constant matrix_float4x4 &transformation [[ buffer(UTMVertexInputIndexTransform) ]],
3839
constant bool *hasAlpha [[ buffer(UTMVertexInputIndexHasAlpha) ]])
3940

4041
{
4142

4243
RasterizerData out;
44+
45+
// Transform the vertex
46+
vector_float4 position = transformation * float4(vertexArray[vertexID].position,0,1);
4347

4448
// Index into our array of positions to get the current vertex
4549
// Our positions are specified in pixel dimensions (i.e. a value of 100 is 100 pixels from
4650
// the origin)
47-
float2 pixelSpacePosition = vertexArray[vertexID].position.xy;
51+
float2 pixelSpacePosition = position.xy;
4852

4953
// Get the size of the drawable so that we can convert to normalized device coordinates,
5054
float2 viewportSize = float2(*viewportSizePointer);

0 commit comments

Comments
 (0)