metal: use a projection matrix instead of manually transforming vertices into clip space on the CPU.
parent
49df65c25a
commit
e24dc9053b
|
@ -324,7 +324,7 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
data.mtlpipelinecopylinear = [[NSMutableArray alloc] init];
|
||||
MakePipelineStates(data, data.mtlpipelinecopylinear, @"SDL texture pipeline (linear)", @"SDL_Copy_vertex", @"SDL_Copy_fragment_linear");
|
||||
|
||||
static const float clearverts[] = { -1, -1, -1, 3, 3, -1 };
|
||||
static const float clearverts[] = { 0, 0, 0, 3, 3, 0 };
|
||||
data.mtlbufclearverts = [data.mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined];
|
||||
data.mtlbufclearverts.label = @"SDL_RenderClear vertices";
|
||||
|
||||
|
@ -504,6 +504,39 @@ METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
|
|||
return 0;
|
||||
}}
|
||||
|
||||
static int
|
||||
METAL_SetOrthographicProjection(SDL_Renderer *renderer, int w, int h)
|
||||
{ @autoreleasepool {
|
||||
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
||||
float projection[4][4];
|
||||
|
||||
if (!w || !h) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prepare an orthographic projection */
|
||||
projection[0][0] = 2.0f / w;
|
||||
projection[0][1] = 0.0f;
|
||||
projection[0][2] = 0.0f;
|
||||
projection[0][3] = 0.0f;
|
||||
projection[1][0] = 0.0f;
|
||||
projection[1][1] = -2.0f / h;
|
||||
projection[1][2] = 0.0f;
|
||||
projection[1][3] = 0.0f;
|
||||
projection[2][0] = 0.0f;
|
||||
projection[2][1] = 0.0f;
|
||||
projection[2][2] = 0.0f;
|
||||
projection[2][3] = 0.0f;
|
||||
projection[3][0] = -1.0f;
|
||||
projection[3][1] = 1.0f;
|
||||
projection[3][2] = 0.0f;
|
||||
projection[3][3] = 1.0f;
|
||||
|
||||
// !!! FIXME: This should be in a buffer...
|
||||
[data.mtlcmdencoder setVertexBytes:projection length:sizeof(float)*16 atIndex:2];
|
||||
return 0;
|
||||
}}
|
||||
|
||||
static int
|
||||
METAL_UpdateViewport(SDL_Renderer * renderer)
|
||||
{ @autoreleasepool {
|
||||
|
@ -517,6 +550,7 @@ METAL_UpdateViewport(SDL_Renderer * renderer)
|
|||
viewport.znear = 0.0;
|
||||
viewport.zfar = 1.0;
|
||||
[data.mtlcmdencoder setViewport:viewport];
|
||||
METAL_SetOrthographicProjection(renderer, renderer->viewport.w, renderer->viewport.h);
|
||||
return 0;
|
||||
}}
|
||||
|
||||
|
@ -563,6 +597,7 @@ METAL_RenderClear(SDL_Renderer * renderer)
|
|||
viewport.zfar = 1.0;
|
||||
|
||||
// Draw a simple filled fullscreen triangle now.
|
||||
METAL_SetOrthographicProjection(renderer, 1, 1);
|
||||
[data.mtlcmdencoder setViewport:viewport];
|
||||
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
|
||||
[data.mtlcmdencoder setVertexBuffer:data.mtlbufclearverts offset:0 atIndex:0];
|
||||
|
@ -577,26 +612,11 @@ METAL_RenderClear(SDL_Renderer * renderer)
|
|||
viewport.znear = 0.0;
|
||||
viewport.zfar = 1.0;
|
||||
[data.mtlcmdencoder setViewport:viewport];
|
||||
METAL_SetOrthographicProjection(renderer, renderer->viewport.w, renderer->viewport.h);
|
||||
|
||||
return 0;
|
||||
}}
|
||||
|
||||
// normalize a value from 0.0f to len into -1.0f to 1.0f.
|
||||
static inline float
|
||||
normx(const float _val, const float len)
|
||||
{
|
||||
const float val = (_val < 0.0f) ? 0.0f : (_val > len) ? len : _val;
|
||||
return (((val + 0.5f) / len) * 2.0f) - 1.0f;
|
||||
}
|
||||
|
||||
// normalize a value from 0.0f to len into -1.0f to 1.0f.
|
||||
static inline float
|
||||
normy(const float _val, const float len)
|
||||
{
|
||||
const float val = (_val <= 0.0f) ? len : (_val >= len) ? 0.0f : (len - _val);
|
||||
return (((val - 0.5f) / len) * 2.0f) - 1.0f;
|
||||
}
|
||||
|
||||
// normalize a value from 0.0f to len into 0.0f to 1.0f.
|
||||
static inline float
|
||||
normtex(const float _val, const float len)
|
||||
|
@ -611,12 +631,7 @@ DrawVerts(SDL_Renderer * renderer, const SDL_FPoint * points, int count,
|
|||
{ @autoreleasepool {
|
||||
METAL_ActivateRenderer(renderer);
|
||||
|
||||
const size_t vertlen = (sizeof (float) * 2) * count;
|
||||
float *verts = SDL_malloc(vertlen);
|
||||
if (!verts) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
const size_t vertlen = sizeof(SDL_FPoint) * count;
|
||||
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
||||
|
||||
// !!! FIXME: render color should live in a dedicated uniform buffer.
|
||||
|
@ -624,21 +639,8 @@ DrawVerts(SDL_Renderer * renderer, const SDL_FPoint * points, int count,
|
|||
|
||||
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
|
||||
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
|
||||
|
||||
const float w = (float)renderer->viewport.w;
|
||||
const float h = (float)renderer->viewport.h;
|
||||
|
||||
// !!! FIXME: we can convert this in the shader. This will save the malloc and for-loop, but we still need to upload.
|
||||
float *ptr = verts;
|
||||
for (int i = 0; i < count; i++, points++) {
|
||||
*ptr = normx(points->x, w); ptr++;
|
||||
*ptr = normy(points->y, h); ptr++;
|
||||
}
|
||||
|
||||
[data.mtlcmdencoder setVertexBytes:verts length:vertlen atIndex:0];
|
||||
[data.mtlcmdencoder setVertexBytes:points length:vertlen atIndex:0];
|
||||
[data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
|
||||
|
||||
SDL_free(verts);
|
||||
return 0;
|
||||
}}
|
||||
|
||||
|
@ -666,17 +668,14 @@ METAL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int coun
|
|||
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
|
||||
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
|
||||
|
||||
const float w = (float)renderer->viewport.w;
|
||||
const float h = (float)renderer->viewport.h;
|
||||
|
||||
for (int i = 0; i < count; i++, rects++) {
|
||||
if ((rects->w <= 0.0f) || (rects->h <= 0.0f)) continue;
|
||||
|
||||
const float verts[] = {
|
||||
normx(rects->x, w), normy(rects->y + rects->h, h),
|
||||
normx(rects->x, w), normy(rects->y, h),
|
||||
normx(rects->x + rects->w, w), normy(rects->y + rects->h, h),
|
||||
normx(rects->x + rects->w, w), normy(rects->y, h)
|
||||
rects->x, rects->y + rects->h,
|
||||
rects->x, rects->y,
|
||||
rects->x + rects->w, rects->y + rects->h,
|
||||
rects->x + rects->w, rects->y,
|
||||
};
|
||||
|
||||
[data.mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0];
|
||||
|
@ -693,16 +692,14 @@ METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
|||
METAL_ActivateRenderer(renderer);
|
||||
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
||||
METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
||||
const float w = (float)renderer->viewport.w;
|
||||
const float h = (float)renderer->viewport.h;
|
||||
const float texw = (float) texturedata.mtltexture.width;
|
||||
const float texh = (float) texturedata.mtltexture.height;
|
||||
|
||||
const float xy[] = {
|
||||
normx(dstrect->x, w), normy(dstrect->y + dstrect->h, h),
|
||||
normx(dstrect->x, w), normy(dstrect->y, h),
|
||||
normx(dstrect->x + dstrect->w, w), normy(dstrect->y + dstrect->h, h),
|
||||
normx(dstrect->x + dstrect->w, w), normy(dstrect->y, h)
|
||||
dstrect->x, dstrect->y + dstrect->h,
|
||||
dstrect->x, dstrect->y,
|
||||
dstrect->x + dstrect->w, dstrect->y + dstrect->h,
|
||||
dstrect->x + dstrect->w, dstrect->y
|
||||
};
|
||||
|
||||
const float uv[] = {
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
#include <metal_texture>
|
||||
#include <metal_matrix>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct SolidVertex
|
||||
struct SolidVertexOutput
|
||||
{
|
||||
float4 position [[position]];
|
||||
float pointSize [[point_size]];
|
||||
};
|
||||
|
||||
vertex SolidVertex SDL_Solid_vertex(constant float2 *position [[buffer(0)]], uint vid [[vertex_id]])
|
||||
vertex SolidVertexOutput SDL_Solid_vertex(const device float2 *position [[buffer(0)]],
|
||||
constant float4x4 &projection [[buffer(2)]],
|
||||
uint vid [[vertex_id]])
|
||||
{
|
||||
SolidVertex v;
|
||||
v.position = float4(position[vid].x, position[vid].y, 0.0f, 1.0f);
|
||||
SolidVertexOutput v;
|
||||
v.position = projection * float4(position[vid].x, position[vid].y, 0.0f, 1.0f);
|
||||
v.pointSize = 0.5f;
|
||||
return v;
|
||||
}
|
||||
|
@ -21,27 +24,34 @@ fragment float4 SDL_Solid_fragment(constant float4 &col [[buffer(0)]])
|
|||
return col;
|
||||
}
|
||||
|
||||
struct CopyVertex
|
||||
struct CopyVertexOutput
|
||||
{
|
||||
float4 position [[position]];
|
||||
float2 texcoord;
|
||||
};
|
||||
|
||||
vertex CopyVertex SDL_Copy_vertex(constant float2 *position [[buffer(0)]], constant float2 *texcoords [[buffer(1)]], uint vid [[vertex_id]])
|
||||
vertex CopyVertexOutput SDL_Copy_vertex(const device float2 *position [[buffer(0)]],
|
||||
const device float2 *texcoords [[buffer(1)]],
|
||||
constant float4x4 &projection [[buffer(2)]],
|
||||
uint vid [[vertex_id]])
|
||||
{
|
||||
CopyVertex v;
|
||||
v.position = float4(position[vid].x, position[vid].y, 0.0f, 1.0f);
|
||||
CopyVertexOutput v;
|
||||
v.position = projection * float4(position[vid].x, position[vid].y, 0.0f, 1.0f);
|
||||
v.texcoord = texcoords[vid];
|
||||
return v;
|
||||
}
|
||||
|
||||
fragment float4 SDL_Copy_fragment_nearest(CopyVertex vert [[stage_in]], constant float4 &col [[buffer(0)]], texture2d<float> tex [[texture(0)]])
|
||||
fragment float4 SDL_Copy_fragment_nearest(CopyVertexOutput vert [[stage_in]],
|
||||
constant float4 &col [[buffer(0)]],
|
||||
texture2d<float> tex [[texture(0)]])
|
||||
{
|
||||
constexpr sampler s(coord::normalized, address::clamp_to_edge, filter::nearest);
|
||||
return tex.sample(s, vert.texcoord) * col;
|
||||
}
|
||||
|
||||
fragment float4 SDL_Copy_fragment_linear(CopyVertex vert [[stage_in]], constant float4 &col [[buffer(0)]], texture2d<float> tex [[texture(0)]])
|
||||
fragment float4 SDL_Copy_fragment_linear(CopyVertexOutput vert [[stage_in]],
|
||||
constant float4 &col [[buffer(0)]],
|
||||
texture2d<float> tex [[texture(0)]])
|
||||
{
|
||||
constexpr sampler s(coord::normalized, address::clamp_to_edge, filter::linear);
|
||||
return tex.sample(s, vert.texcoord) * col;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue