metal backend functional

This commit is contained in:
a dinosaur 2022-11-19 00:42:33 +11:00
parent 8ce1cca1ef
commit a75e480155
10 changed files with 595 additions and 17 deletions

View File

@ -2,14 +2,25 @@ cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
project(padlab C)
set(TARGET padlab)
option(USE_OPENGL "Use OpenGL for drawing (WIP)" OFF)
if (USE_OPENGL)
option(USE_METAL "use Metal for drawing" ${APPLE})
if (USE_METAL)
option(USE_OPENGL "Use OpenGL for drawing (WIP)" OFF)
option(USE_OPENGL_LEGACY "Use legacy OpenGL for drawing" OFF)
if (USE_OPENGL_LEGACY)
message(FATAL_ERROR "USE_OPENGL and USE_OPENGL_LEGACY are both ON but only one backend can be used at a time, turn one OFF and regenerate. (or delete cache and try again)")
if (USE_OPENGL)
message(FATAL_ERROR "USE_METAL and USE_OPENGL are both ON but only one backend can be used at a time, turn one OFF and regenerate. (or delete cache and try again)")
elseif (USE_OPENGL_LEGACY)
message(FATAL_ERROR "USE_METAL and USE_OPENGL_LEGACY are both ON but only one backend can be used at a time, turn one OFF and regenerate. (or delete cache and try again)")
endif()
else()
option(USE_OPENGL_LEGACY "Use legacy OpenGL for drawing" ON)
option(USE_OPENGL "Use OpenGL for drawing (WIP)" OFF)
if (USE_OPENGL)
option(USE_OPENGL_LEGACY "Use legacy OpenGL for drawing" OFF)
if (USE_OPENGL_LEGACY)
message(FATAL_ERROR "USE_OPENGL and USE_OPENGL_LEGACY are both ON but only one backend can be used at a time, turn one OFF and regenerate. (or delete cache and try again)")
endif()
else()
option(USE_OPENGL_LEGACY "Use legacy OpenGL for drawing" ON)
endif()
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")

View File

@ -10,14 +10,18 @@ function (bin2h_compile)
set(DEPENDS)
set(COMMAND ${BIN2H_EXECUTABLE})
foreach (BIN ${ARGS_BIN})
set(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${BIN})
foreach (SOURCE ${ARGS_BIN})
if (NOT IS_ABSOLUTE ${SOURCE})
set(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE})
endif()
list(APPEND DEPENDS ${SOURCE})
list(APPEND COMMAND "-b" "${SOURCE}")
endforeach()
foreach (TXT ${ARGS_TXT})
set(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${TXT})
foreach (SOURCE ${ARGS_TXT})
if (NOT IS_ABSOLUTE ${SOURCE})
set(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE})
endif()
list(APPEND DEPENDS ${SOURCE})
list(APPEND COMMAND "-t" "${SOURCE}")
endforeach()

55
cmake/MetalHelper.cmake Normal file
View File

@ -0,0 +1,55 @@
include(CMakeParseArguments) # 3.4 and lower compatibility
function (_xrun_find_program OUTPUT NAME)
find_program(XCRUN_EXECUTABLE xcrun REQUIRED)
execute_process(COMMAND ${XCRUN_EXECUTABLE} -sdk macosx -f ${NAME} OUTPUT_VARIABLE EXECUTABLE_PATH)
get_filename_component(EXECUTABLE_DIR ${EXECUTABLE_PATH} DIRECTORY)
find_program(${OUTPUT} ${NAME} PATHS ${EXECUTABLE_DIR} REQUIRED)
endfunction()
function (metal_compile)
cmake_parse_arguments(ARGS "DEBUG" "OUTPUT" "SOURCES;CFLAGS" ${ARGN})
_xrun_find_program(METAL_EXECUTABLE metal)
if (ARGS_DEBUG)
_xrun_find_program(METAL_DSYMUTIL_EXECUTABLE metal-dsymutil)
list(APPEND CFLAGS -frecord-sources)
else()
_xrun_find_program(METALLIB_EXECUTABLE metallib)
endif()
set(AIR_OBJECTS)
foreach (SOURCE ${ARGS_SOURCES})
if (${CMAKE_VERSION} VERSION_GREATER 3.3)
get_filename_component(SOURCE "${SOURCE}" REALPATH)
else()
if (NOT IS_ABSOLUTE ${SOURCE})
set(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE})
endif()
endif()
get_filename_component(BASENAME "${SOURCE}" NAME)
set(OUTPUT_AIR ${BASENAME}.air)
add_custom_command(
COMMAND ${METAL_EXECUTABLE}
ARGS ${ARGS_CFLAGS} -c ${SOURCE} -o ${OUTPUT_AIR}
DEPENDS ${METAL_EXECUTABLE} ${SOURCE}
OUTPUT ${OUTPUT_AIR})
list(APPEND AIR_OBJECTS ${OUTPUT_AIR})
endforeach()
if (NOT ARGS_DEBUG)
add_custom_command(
COMMAND ${METALLIB_EXECUTABLE}
ARGS ${LDFLAGS} ${AIR_OBJECTS} -o ${ARGS_OUTPUT}
DEPENDS ${METALLIB_EXECUTABLE} ${AIR_OBJECTS}
OUTPUT ${ARGS_OUTPUT})
else()
set(OUTPUTSYM ${ARGS_OUTPUT}sym)
add_custom_command(
COMMAND ${METAL_EXECUTABLE} ARGS -frecord-sources ${AIR_OBJECTS} -o ${ARGS_OUTPUT}
COMMAND ${METAL_DSYMUTIL_EXECUTABLE} ARGS -flat -remove-source ${ARGS_OUTPUT}
DEPENDS ${METAL_EXECUTABLE} ${METAL_DSYMUTIL_EXECUTABLE} ${AIR_OBJECTS}
OUTPUT ${ARGS_OUTPUT} ${OUTPUTSYM})
endif()
endfunction()

View File

@ -2,14 +2,24 @@ set(SOURCES
maths.h
draw.h
draw_common.c
$<$<NOT:$<OR:$<BOOL:${USE_OPENGL}>,$<BOOL:${USE_OPENGL_LEGACY}>>>:draw.c>
$<$<NOT:$<OR:$<BOOL:${USE_METAL}>,$<BOOL:${USE_OPENGL}>,$<BOOL:${USE_OPENGL_LEGACY}>>>:draw.c>
$<$<BOOL:${USE_METAL}>:draw_metal.m metal_shader_types.h>
$<$<BOOL:${USE_OPENGL}>:draw_opengl_core.c>
$<$<BOOL:${USE_OPENGL_LEGACY}>:draw_opengl.c>
stick.h
stick.c
analogue.c)
if (USE_OPENGL)
if (USE_METAL)
find_library(METAL Metal REQUIRED)
find_library(FOUNDATION Foundation REQUIRED)
find_library(QUARTZCORE QuartzCore REQUIRED)
include(MetalHelper)
metal_compile(OUTPUT shader.metallib SOURCES shader.metal)
include(BinHelper)
bin2h_compile(OUTPUT metalShader.h BIN ${CMAKE_CURRENT_BINARY_DIR}/shader.metallib)
list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/metalShader.h)
elseif (USE_OPENGL)
include(GL3WHelper)
add_gl3w(gl3w)
include(BinHelper)
@ -19,14 +29,16 @@ endif()
add_executable(${TARGET} ${SOURCES})
target_include_directories(${TARGET} PRIVATE
$<$<BOOL:${USE_OPENGL}>:${CMAKE_CURRENT_BINARY_DIR}>)
$<$<OR:$<BOOL:${USE_METAL}>,$<BOOL:${USE_OPENGL}>>:${CMAKE_CURRENT_BINARY_DIR}>)
target_link_libraries(${TARGET}
$<$<PLATFORM_ID:Windows>:SDL2::SDL2main>
SDL2::SDL2
$<$<BOOL:${USE_METAL}>:${METAL} ${QUARTZCORE} ${FOUNDATION}>
$<$<OR:$<BOOL:${USE_OPENGL}>,$<BOOL:${USE_OPENGL_LEGACY}>>:OpenGL::GL>
$<$<BOOL:${USE_OPENGL}>:gl3w>
$<$<BOOL:${GNU}>:m>)
target_compile_options(${TARGET} PRIVATE
$<$<BOOL:${GNU}>:-Wall -Wextra -pedantic -Wno-unused-parameter>)
target_compile_definitions(${TARGET} PRIVATE
$<$<BOOL:${USE_METAL}>:USE_METAL>
$<$<OR:$<BOOL:${USE_OPENGL}>,$<BOOL:${USE_OPENGL_LEGACY}>>:USE_OPENGL>)

View File

@ -37,6 +37,8 @@ int main(int argc, char** argv)
const int winpos = SDL_WINDOWPOS_CENTERED;
#ifdef USE_OPENGL
const int winflg = SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI;
#elif defined USE_METAL
const int winflg = SDL_WINDOW_RESIZABLE | SDL_WINDOW_METAL | SDL_WINDOW_ALLOW_HIGHDPI;
#else
const int winflg = SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
#endif

430
src/draw_metal.m Normal file
View File

@ -0,0 +1,430 @@
#include "draw.h"
#include "metalShader.h"
#include "metal_shader_types.h"
#include "maths.h"
#include <SDL_metal.h>
#import <Metal/Metal.h>
#import <QuartzCore/CAMetalLayer.h>
@interface MetalRenderer : NSObject
@property (nonatomic, readwrite) uint32_t drawColour;
- (id) init:(SDL_Window*)window;
- (void) dealloc;
- (unsigned) resizeBuffer:(void**)buf itemSize:(unsigned)nsz reserveLen:(unsigned)reserve requiredNum:(unsigned)count;
- (void) resizeMtlBuffer:(id <MTLBuffer>*)buf length:(unsigned)length;
- (size) getDrawSize;
- (void) setClear:(uint32_t)colour;
- (void) setView:(size)viewportSize;
- (void) clearVerticesAndIndices;
- (void) reserveVertices:(unsigned)count;
- (void) reserveIndices:(unsigned)count;
- (uint16_t) queueVertex:(int)x :(int)y;
- (uint16_t) queueVertexF:(float)x :(float)y;
- (uint16_t) queueIndex:(uint16_t)idx;
- (void) queueIndices:(uint16_t*)idcs count:(unsigned)count;
- (void) present;
@end
#define DRAWLIST_CHUNK_SIZE 480
#define DRAWLIST_INIT_SIZE (DRAWLIST_CHUNK_SIZE)
@implementation MetalRenderer
{
SDL_Window* _window;
SDL_MetalView _view;
id<MTLDevice> _dev;
CAMetalLayer* _layer;
id<MTLCommandQueue> _queue;
MTLRenderPassDescriptor* _passDesc;
id<MTLRenderPipelineState> _pso; // gonna fine u on the belgrave & lillydale line
MTLViewport _viewport;
vector_float4 _drawColourF;
ShaderVertex* _vtxList;
uint16_t* _idxList;
unsigned _vtxListCount, _vtxListReserve, _idxListCount, _idxListReserve;
id<MTLBuffer> _vtxMtlBuffer, _idxMtlBuffer;
}
- (id) init:(SDL_Window*)window
{
if (!(self = [super init]))
return nil;
self.drawColour = BLACK;
_vtxList = NULL;
_idxList = NULL;
_vtxListCount = 0;
_idxListCount = 0;
_vtxListReserve = 0;
_idxListReserve = 0;
_vtxMtlBuffer = nil;
_idxMtlBuffer = nil;
// Create Metal view
_window = window;
_view = SDL_Metal_CreateView(_window);
// Get Metal device
#if 1
_dev = MTLCreateSystemDefaultDevice();
fprintf(stderr, "Default MTL device \"%s\"\n", [_dev.name UTF8String]);
#else
NSArray<id<MTLDevice>>* devices = MTLCopyAllDevices();
for (id<MTLDevice> i in devices)
{
if (!i.supportsRaytracing) continue;
if (_dev && i.isLowPower) continue;
_dev = i;
}
fprintf(stderr, "You have selected funny device \"%s\"\n", [_dev.name UTF8String]);
#endif
// Setup Metal layer
_layer = (__bridge CAMetalLayer*)SDL_Metal_GetLayer(_view);
_layer.device = _dev;
_layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
_queue = [_dev newCommandQueue];
_passDesc = [MTLRenderPassDescriptor new];
_passDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
_passDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
[self setClear:self.drawColour]; // passDesc.colorAttachments[0].clearColor = curColour
// Compile shady bois
__autoreleasing NSError* booboo = nil;
dispatch_data_t shaderData = dispatch_data_create(shader_metallib, SHADER_METALLIB_SIZE, nil, nil);
id<MTLLibrary> lib = [_dev newLibraryWithData:shaderData error:&booboo];
if (!lib)
{
fprintf(stderr, "Metal shader compilation failed:\n%s\n", [[booboo localizedDescription] UTF8String]);
return nil;
}
id<MTLFunction> vertPrg = [lib newFunctionWithName:@"vertexMain"];
id<MTLFunction> fragPrg = [lib newFunctionWithName:@"fragmentMain"];
// Setup render pipeline state
MTLRenderPipelineDescriptor* pipeDesc = [[MTLRenderPipelineDescriptor alloc] init];
pipeDesc.vertexFunction = vertPrg;
pipeDesc.fragmentFunction = fragPrg;
pipeDesc.colorAttachments[0].pixelFormat = _layer.pixelFormat;
_pso = [_dev newRenderPipelineStateWithDescriptor:pipeDesc error:&booboo];
if (!_pso)
{
fprintf(stderr, "Your Myki has expired and u have been slapped with a $237 fine: %s\n", [[booboo localizedDescription] UTF8String]);
return nil;
}
[pipeDesc release];
// Set viewport
[self setView:[self getDrawSize]];
return self;
}
- (void) dealloc
{
SDL_Metal_DestroyView(_view);
[super dealloc];
}
- (unsigned) resizeBuffer:(void**)buf itemSize:(unsigned)nsz reserveLen:(unsigned)reserve requiredNum:(unsigned)count
{
if (*buf && count * nsz <= reserve)
return reserve;
// Calculate new capacity
unsigned newCapacity = (count + DRAWLIST_CHUNK_SIZE - 1) / DRAWLIST_CHUNK_SIZE * DRAWLIST_CHUNK_SIZE;
if (!*buf)
newCapacity = MAX(newCapacity, DRAWLIST_INIT_SIZE);
// (Re)allocate and return new reserve size
unsigned newReserve = newCapacity * nsz;
*buf = realloc(*buf, newReserve);
printf("buffer %p %u -> %u\n", *buf, reserve, newReserve);
return newReserve;
}
- (void) resizeMtlBuffer:(id <MTLBuffer>*)buf length:(unsigned)length
{
if (*buf && length <= [*buf length])
return;
printf("mtlBuf %p %lu -> %u\n", (void*)buf, (unsigned long)[*buf length], length);
id<MTLBuffer> new = [_dev newBufferWithLength:length options:MTLResourceStorageModeManaged];
if (*buf)
{
[*buf setPurgeableState:MTLPurgeableStateEmpty];
[*buf release];
}
*buf = new;
}
- (size) getDrawSize
{
size out;
SDL_Metal_GetDrawableSize(_window, &out.w, &out.h);
return out;
}
- (void)setDrawColour:(uint32_t)colour
{
_drawColour = colour;
const float mul = 1.0f / 255.0f;
_drawColourF = (vector_float4){
(float)((colour & 0xFF000000) >> 24) * mul,
(float)((colour & 0x00FF0000) >> 16) * mul,
(float)((colour & 0x0000FF00) >> 8) * mul,
(float)((colour & 0x000000FF)) * mul };
}
- (void) setClear:(uint32_t)colour
{
const double mul = 1.0 / 255.0;
_passDesc.colorAttachments[0].clearColor = MTLClearColorMake(
(double)((colour & 0xFF000000) >> 24) * mul,
(double)((colour & 0x00FF0000) >> 16) * mul,
(double)((colour & 0x0000FF00) >> 8) * mul,
(double)((colour & 0x000000FF)) * mul);
}
- (void) setView:(size)viewportSize
{
_viewport = (MTLViewport){
.originX = 0.0, .originY = 0.0,
.width = viewportSize.w, .height = viewportSize.h,
.znear = 1.0, .zfar = -1.0 };
}
- (void) clearVerticesAndIndices
{
_vtxListCount = 0;
_idxListCount = 0;
}
- (void) reserveVertices:(unsigned)count
{
count += _vtxListCount;
if (count * sizeof(ShaderVertex) > _vtxListReserve)
_vtxListReserve = [self resizeBuffer:(void**)&_vtxList
itemSize:sizeof(ShaderVertex) reserveLen:_vtxListReserve requiredNum:count];
}
- (void) reserveIndices:(unsigned)count
{
count += _idxListCount;
if (count * sizeof(uint16_t) > _idxListReserve)
_idxListReserve = [self resizeBuffer:(void**)&_idxList
itemSize:sizeof(uint16_t) reserveLen:_idxListReserve requiredNum:count];
}
- (uint16_t) queueVertex:(int)x :(int)y
{
if (_vtxListCount * sizeof(ShaderVertex) >= _vtxListReserve)
[self reserveVertices:1];
_vtxList[_vtxListCount] = (ShaderVertex){
.position = { (float)x, (float)y },
.colour = _drawColourF };
return _vtxListCount++;
}
- (uint16_t) queueVertexF:(float)x :(float)y
{
if (_vtxListCount * sizeof(ShaderVertex) >= _vtxListReserve)
[self reserveVertices:1];
_vtxList[_vtxListCount] = (ShaderVertex){
.position = { x, y },
.colour = _drawColourF };
return _vtxListCount++;
}
- (uint16_t) queueIndex:(uint16_t)idx
{
if (_idxListCount * sizeof(uint16_t) >= _idxListReserve)
[self reserveIndices:1];
_idxList[_idxListCount++] = idx;
return idx;
}
- (void) queueIndices:(uint16_t*)idcs count:(unsigned)count
{
if ((_idxListCount + count) * sizeof(uint16_t) >= _idxListReserve)
[self reserveIndices:count];
memcpy(&_idxList[_idxListCount], idcs, count * sizeof(uint16_t));
_idxListCount += count;
}
- (void) present
{
// Create or recreate buffers if needed & fill with data
if (_vtxListCount)
{
unsigned copyLen = _vtxListCount * sizeof(ShaderVertex);
if (_vtxMtlBuffer == nil || [_vtxMtlBuffer length] < copyLen)
[self resizeMtlBuffer:&_vtxMtlBuffer length:_vtxListReserve];
memcpy(_vtxMtlBuffer.contents, _vtxList, copyLen);
}
if (_idxListCount)
{
unsigned copyLen = _idxListCount * sizeof(uint16_t);
if (_idxMtlBuffer == nil || [_idxMtlBuffer length] < copyLen)
[self resizeMtlBuffer:&_idxMtlBuffer length:_idxListReserve];
memcpy(_idxMtlBuffer.contents, _idxList, copyLen);
}
@autoreleasepool
{
id<CAMetalDrawable> rt = [_layer nextDrawable];
_passDesc.colorAttachments[0].texture = rt.texture;
id<MTLCommandBuffer> cmdBuf = [_queue commandBuffer];
id<MTLRenderCommandEncoder> enc = [cmdBuf renderCommandEncoderWithDescriptor:_passDesc];
[enc setViewport:_viewport];
[enc setCullMode:MTLCullModeNone];
[enc setRenderPipelineState:_pso];
if (_vtxMtlBuffer != nil && _idxMtlBuffer != nil)
{
[enc setVertexBuffer:_vtxMtlBuffer offset:0 atIndex:ShaderInputIdxVerticies];
const vector_float2 viewportScale = { (float)(1.0 / _viewport.width), (float)(1.0 / _viewport.height) };
[enc setVertexBytes:&viewportScale length:sizeof(vector_float2) atIndex:ShaderInputViewportScale];
[enc drawIndexedPrimitives:MTLPrimitiveTypeLine
indexCount:_idxListCount indexType:MTLIndexTypeUInt16
indexBuffer:_idxMtlBuffer indexBufferOffset:0];
}
[enc endEncoding];
[cmdBuf presentDrawable:rt]; // u go to software premieres
[cmdBuf commit]; // is that linus torvolds?
// hear songs on pandora radiowo
[self clearVerticesAndIndices];
}
}
@end
static MetalRenderer* renderer = nil;
void DrawWindowHints(void) {}
int InitDraw(SDL_Window* window)
{
renderer = [[MetalRenderer alloc] init:window];
if (!renderer)
return -1;
return 0;
}
void QuitDraw(void)
{
[renderer release];
}
size GetDrawSizeInPixels(void)
{
return renderer ? [renderer getDrawSize] : (size){ 0, 0 };
}
void SetDrawViewport(size size)
{
[renderer setView:size];
}
void SetDrawColour(uint32_t c)
{
renderer.drawColour = c;
}
void DrawClear(void)
{
[renderer setClear:renderer.drawColour];
[renderer clearVerticesAndIndices];
}
void DrawPoint(int x, int y)
{
DrawCircleSteps(x, y, 1, 4);
}
void DrawRect(int x, int y, int w, int h)
{
[renderer reserveVertices:4];
uint16_t i00 = [renderer queueVertex:x :y];
uint16_t i10 = [renderer queueVertex:x + w :y];
uint16_t i11 = [renderer queueVertex:x + w :y + h];
uint16_t i01 = [renderer queueVertex:x :y + h];
uint16_t indices[] = { i00, i10, i10, i11, i11, i01, i01, i00 };
[renderer queueIndices:indices count:sizeof(indices) / sizeof(uint16_t)];
}
void DrawLine(int x1, int y1, int x2, int y2)
{
[renderer queueIndex:[renderer queueVertex:x1 :y1]];
[renderer queueIndex:[renderer queueVertex:x2 :y2]];
}
void DrawCircleSteps(int x, int y, int r, int steps)
{
const float fx = (float)x, fy = (float)y;
const float stepSz = (float)TAU / (float)abs(steps);
const float mag = (float)r;
// Draw whole circle in a single loop
[renderer reserveVertices:steps];
[renderer reserveIndices:steps * 2];
uint16_t base = [renderer queueIndex:[renderer queueVertex:x + r :y]];
for (int i = 1; i < steps; ++i)
{
const float theta = stepSz * (float)i;
uint16_t ii = [renderer queueVertexF:fx + cosf(theta) * mag :fy + sinf(theta) * mag];
[renderer queueIndices:(uint16_t[]){ ii, ii } count:2];
}
[renderer queueIndex:base];
}
void DrawArcSteps(int x, int y, int r, int startAng, int endAng, int steps)
{
const float fx = (float)x, fy = (float)y;
const float magw = (float)r, magh = (float)r;
const float start = (float)startAng * (float)DEG2RAD;
const float stepSz = (float)(endAng - startAng) / (float)abs(steps) * (float)DEG2RAD;
[renderer reserveVertices:steps];
[renderer reserveIndices:steps * 2];
uint16_t ii = [renderer queueVertexF:fx + cosf(start) * magw :fy - sinf(start) * magh];
for (int i = 1; i <= steps; ++i)
{
const float theta = start + stepSz * (float)i;
uint16_t iii = [renderer queueVertexF:fx + cosf(theta) * magw :fy - sinf(theta) * magh];
[renderer queueIndices:(uint16_t[]){ ii, iii } count:2];
ii = iii;
}
}
void DrawPresent(void)
{
[renderer present];
}

18
src/metal_shader_types.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef METAL_SHADER_TYPES_H
#define METAL_SHADER_TYPES_H
#include <simd/simd.h>
typedef enum
{
ShaderInputIdxVerticies = 0,
ShaderInputViewportScale = 1
} ShaderInputIdx;
typedef struct
{
vector_float2 position;
vector_float4 colour;
} ShaderVertex;
#endif//METAL_SHADER_TYPES_H

27
src/shader.metal Normal file
View File

@ -0,0 +1,27 @@
#include "metal_shader_types.h"
#include <metal_stdlib>
using namespace metal;
struct FragmentInput
{
float4 position [[position]];
float4 colour;
};
vertex FragmentInput vertexMain(
uint vertexId [[vertex_id]],
device const ShaderVertex* v [[buffer(ShaderInputIdxVerticies)]],
constant vector_float2& viewportScale [[buffer(ShaderInputViewportScale)]])
{
float2 eyePos = v[vertexId].position * viewportScale * float2(2.0f, -2.0f) - float2(1.0f, -1.0f);
FragmentInput o;
o.position = float4(eyePos, 0.0f, 1.0f);
o.colour = v[vertexId].colour;
return o;
}
fragment float4 fragmentMain(FragmentInput in [[stage_in]])
{
return in.colour;
}

View File

@ -20,7 +20,8 @@ typedef struct { int x, y, w, h; } rect;
#define MKRGB(C) (uint32_t)(((C) << 8) | 0x000000FF)
#define WHITE 0xFFFFFFFF
#define BLACK MKRGB(0x000000)
#define WHITE MKRGB(0xFFFFFF)
#define GREY1 MKGREY(0x1F, 0xFF)
#define GREY2 MKGREY(0x37, 0xFF)
#define GREY3 MKGREY(0x4F, 0xFF)

View File

@ -3,6 +3,7 @@
import sys
from pathlib import Path
from typing import BinaryIO, TextIO
from os import SEEK_SET, SEEK_END
import re
@ -16,7 +17,24 @@ def sanitise_label(label: str) -> str:
def bin2h(name: str, binf: BinaryIO, h: TextIO):
raise NotImplementedError
label = sanitise_label(name)
binf.seek(0, SEEK_END)
length = binf.tell()
binf.seek(0, SEEK_SET)
h.write(f"#define {label.upper()}_SIZE {length}\n")
whitespace = "\t"
h.write(f"static const unsigned char {label}[{length}] = {{\n{whitespace}")
for i, c in enumerate(binf.read()):
if i != 0:
h.write(", ")
if i % 16 == 0:
h.write(f"\n{whitespace}")
h.write(f"0x{c:02X}")
h.write("\n};\n")
def txt2h(name: str, txt: TextIO, h: TextIO):
@ -93,16 +111,16 @@ def main():
path = Path(i)
with path.open("rb") as file:
bin2h(path.name, file, h)
h.write("\n")
# Write texts
for i in txtfiles:
path = Path(i)
with path.open("r") as file:
txt2h(path.name, file, h)
h.write("\n")
h.writelines([
"\n",
f"#endif//{guard}\n"])
h.write(f"#endif//{guard}\n")
if __name__ == "__main__":