Quellcode durchsuchen

Added support for custom shaders with the GPU renderer

Added an example of MSDF font rendering with the SDL 2D renderer
Sam Lantinga vor 1 Monat
Ursprung
Commit
2aee105b43

+ 112 - 0
include/SDL3/SDL_render.h

@@ -59,6 +59,7 @@
 #include <SDL3/SDL_rect.h>
 #include <SDL3/SDL_surface.h>
 #include <SDL3/SDL_video.h>
+#include <SDL3/SDL_gpu.h>
 
 #include <SDL3/SDL_begin_code.h>
 /* Set up for C function definitions, even when using C++ */
@@ -2709,6 +2710,117 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetDefaultTextureScaleMode(SDL_Renderer *re
  */
 extern SDL_DECLSPEC bool SDLCALL SDL_GetDefaultTextureScaleMode(SDL_Renderer *renderer, SDL_ScaleMode *scale_mode);
 
+/**
+ * GPU render state description.
+ *
+ * This structure should be initialized using SDL_INIT_INTERFACE().
+ *
+ * \since This struct is available since SDL 3.4.0.
+ *
+ * \sa SDL_CreateGPURenderState
+ */
+typedef struct SDL_GPURenderStateDesc
+{
+    Uint32 version;                 /**< the version of this interface */
+
+    SDL_GPUShader *fragment_shader; /**< The fragment shader to use when this render state is active */
+
+    Sint32 num_sampler_bindings;    /**< The number of additional fragment samplers to bind when this render state is active */
+    const SDL_GPUTextureSamplerBinding *sampler_bindings;   /** Additional fragment samplers to bind when this render state is active */
+
+    Sint32 num_storage_textures;    /**< The number of storage textures to bind when this render state is active */
+    SDL_GPUTexture *const *storage_textures;    /** Storage textures to bind when this render state is active */
+
+    Sint32 num_storage_buffers;    /**< The number of storage buffers to bind when this render state is active */
+    SDL_GPUBuffer *const *storage_buffers;      /** Storage buffers to bind when this render state is active */
+} SDL_GPURenderStateDesc;
+
+/* Check the size of SDL_GPURenderStateDesc
+ *
+ * If this assert fails, either the compiler is padding to an unexpected size,
+ * or the interface has been updated and this should be updated to match and
+ * the code using this interface should be updated to handle the old version.
+ */
+SDL_COMPILE_TIME_ASSERT(SDL_GPURenderStateDesc_SIZE,
+    (sizeof(void *) == 4 && sizeof(SDL_GPURenderStateDesc) == 32) ||
+    (sizeof(void *) == 8 && sizeof(SDL_GPURenderStateDesc) == 64));
+
+/**
+ * A custom GPU render state.
+ *
+ * \since This struct is available since SDL 3.4.0.
+ *
+ * \sa SDL_CreateGPURenderState
+ * \sa SDL_SetGPURenderStateFragmentUniformData
+ * \sa SDL_SetRenderGPUState
+ * \sa SDL_DestroyGPURenderState
+ */
+typedef struct SDL_GPURenderState SDL_GPURenderState;
+
+/**
+ * Create custom GPU render state.
+ *
+ * \param renderer the renderer to use.
+ * \param desc GPU render state description, initialized using SDL_INIT_INTERFACE().
+ * \returns a custom GPU render state or NULL on failure; call SDL_GetError() for more information.
+ *
+ * \threadsafety This function should be called on the thread that created the renderer.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_SetGPURenderStateFragmentUniformData
+ * \sa SDL_SetRenderGPUState
+ * \sa SDL_DestroyGPURenderState
+ */
+extern SDL_DECLSPEC SDL_GPURenderState * SDLCALL SDL_CreateGPURenderState(SDL_Renderer *renderer, SDL_GPURenderStateDesc *desc);
+
+/**
+ * Set fragment shader uniform variables in a custom GPU render state.
+ *
+ * The data is copied and will be pushed using SDL_PushGPUFragmentUniformData() during draw call execution.
+ *
+ * \param state the state to modify.
+ * \param slot_index the fragment uniform slot to push data to.
+ * \param data client data to write.
+ * \param length the length of the data to write.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \threadsafety This function should be called on the thread that created the renderer.
+ *
+ * \since This function is available since SDL 3.4.0.
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_SetGPURenderStateFragmentUniformData(SDL_GPURenderState *state, Uint32 slot_index, const void *data, Uint32 length);
+
+/**
+ * Set custom GPU render state.
+ *
+ * This function sets custom GPU render state for subsequent draw calls. This allows using custom shaders with the GPU renderer.
+ *
+ * \param renderer the renderer to use.
+ * \param state the state to to use, or NULL to clear custom GPU render state.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \threadsafety This function should be called on the thread that created the renderer.
+ *
+ * \since This function is available since SDL 3.4.0.
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderGPUState(SDL_Renderer *renderer, SDL_GPURenderState *state);
+
+/**
+ * Destroy custom GPU render state.
+ *
+ * \param state the state to destroy.
+ *
+ * \threadsafety This function should be called on the thread that created the renderer.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_CreateGPURenderState
+ */
+extern SDL_DECLSPEC void SDLCALL SDL_DestroyGPURenderState(SDL_GPURenderState *state);
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }

+ 4 - 0
src/dynapi/SDL_dynapi.sym

@@ -1238,6 +1238,10 @@ SDL3_0.0.0 {
     SDL_RenderTexture9GridTiled;
     SDL_SetDefaultTextureScaleMode;
     SDL_GetDefaultTextureScaleMode;
+    SDL_CreateGPURenderState;
+    SDL_SetGPURenderStateFragmentUniformData;
+    SDL_SetRenderGPUState;
+    SDL_DestroyGPURenderState;
     # extra symbols go here (don't modify this line)
   local: *;
 };

+ 4 - 0
src/dynapi/SDL_dynapi_overrides.h

@@ -1263,3 +1263,7 @@
 #define SDL_RenderTexture9GridTiled SDL_RenderTexture9GridTiled_REAL
 #define SDL_SetDefaultTextureScaleMode SDL_SetDefaultTextureScaleMode_REAL
 #define SDL_GetDefaultTextureScaleMode SDL_GetDefaultTextureScaleMode_REAL
+#define SDL_CreateGPURenderState SDL_CreateGPURenderState_REAL
+#define SDL_SetGPURenderStateFragmentUniformData SDL_SetGPURenderStateFragmentUniformData_REAL
+#define SDL_SetRenderGPUState SDL_SetRenderGPUState_REAL
+#define SDL_DestroyGPURenderState SDL_DestroyGPURenderState_REAL

+ 4 - 0
src/dynapi/SDL_dynapi_procs.h

@@ -1271,3 +1271,7 @@ SDL_DYNAPI_PROC(bool,SDL_SetRelativeMouseTransform,(SDL_MouseMotionTransformCall
 SDL_DYNAPI_PROC(bool,SDL_RenderTexture9GridTiled,(SDL_Renderer *a,SDL_Texture *b,const SDL_FRect *c,float d,float e,float f,float g,float h,const SDL_FRect *i,float j),(a,b,c,d,e,f,g,h,i,j),return)
 SDL_DYNAPI_PROC(bool,SDL_SetDefaultTextureScaleMode,(SDL_Renderer *a,SDL_ScaleMode b),(a,b),return)
 SDL_DYNAPI_PROC(bool,SDL_GetDefaultTextureScaleMode,(SDL_Renderer *a,SDL_ScaleMode *b),(a,b),return)
+SDL_DYNAPI_PROC(SDL_GPURenderState*,SDL_CreateGPURenderState,(SDL_Renderer *a,SDL_GPURenderStateDesc *b),(a,b),return)
+SDL_DYNAPI_PROC(bool,SDL_SetGPURenderStateFragmentUniformData,(SDL_GPURenderState *a,Uint32 b,const void *c,Uint32 d),(a,b,c,d),return)
+SDL_DYNAPI_PROC(bool,SDL_SetRenderGPUState,(SDL_Renderer *a,SDL_GPURenderState *b),(a,b),return)
+SDL_DYNAPI_PROC(void,SDL_DestroyGPURenderState,(SDL_GPURenderState *a),(a),)

+ 153 - 0
src/render/SDL_render.c

@@ -346,6 +346,16 @@ static bool FlushRenderCommandsIfTextureNeeded(SDL_Texture *texture)
     return true;
 }
 
+static bool FlushRenderCommandsIfGPURenderStateNeeded(SDL_GPURenderState *state)
+{
+    SDL_Renderer *renderer = state->renderer;
+    if (state->last_command_generation == renderer->render_command_generation) {
+        // the current command queue depends on this state, flush the queue now before it changes
+        return FlushRenderCommands(renderer);
+    }
+    return true;
+}
+
 bool SDL_FlushRenderer(SDL_Renderer *renderer)
 {
     if (!FlushRenderCommands(renderer)) {
@@ -577,6 +587,10 @@ static SDL_RenderCommand *PrepQueueCmdDraw(SDL_Renderer *renderer, const SDL_Ren
                 cmd->data.draw.texture_scale_mode = texture->scaleMode;
             }
             cmd->data.draw.texture_address_mode = SDL_TEXTURE_ADDRESS_CLAMP;
+            cmd->data.draw.gpu_render_state = renderer->gpu_render_state;
+            if (renderer->gpu_render_state) {
+                renderer->gpu_render_state->last_command_generation = renderer->render_command_generation;
+            }
         }
     }
     return cmd;
@@ -5824,3 +5838,142 @@ bool SDL_GetDefaultTextureScaleMode(SDL_Renderer *renderer, SDL_ScaleMode *scale
     }
     return true;
 }
+
+SDL_GPURenderState *SDL_CreateGPURenderState(SDL_Renderer *renderer, SDL_GPURenderStateDesc *desc)
+{
+    CHECK_RENDERER_MAGIC(renderer, false);
+
+    if (!desc) {
+        SDL_InvalidParamError("desc");
+        return NULL;
+    }
+
+    if (desc->version < sizeof(*desc)) {
+        // Update this to handle older versions of this interface
+        SDL_SetError("Invalid desc, should be initialized with SDL_INIT_INTERFACE()");
+        return NULL;
+    }
+
+    if (!desc->fragment_shader) {
+        SDL_SetError("desc->fragment_shader is required");
+        return NULL;
+    }
+
+    SDL_GPUDevice *device = (SDL_GPUDevice *)SDL_GetPointerProperty(renderer->props, SDL_PROP_RENDERER_GPU_DEVICE_POINTER, NULL);
+    if (!device) {
+        SDL_SetError("Renderer isn't associated with a GPU device");
+        return NULL;
+    }
+
+    SDL_GPURenderState *state = (SDL_GPURenderState *)SDL_calloc(1, sizeof(*state));
+    if (!state) {
+        return NULL;
+    }
+
+    state->renderer = renderer;
+    state->fragment_shader = desc->fragment_shader;
+
+    if (desc->num_sampler_bindings > 0) {
+        state->sampler_bindings = (SDL_GPUTextureSamplerBinding *)SDL_calloc(desc->num_sampler_bindings, sizeof(*state->sampler_bindings));
+        if (!state->sampler_bindings) {
+            SDL_DestroyGPURenderState(state);
+            return NULL;
+        }
+        SDL_memcpy(state->sampler_bindings, desc->sampler_bindings, desc->num_sampler_bindings * sizeof(*state->sampler_bindings));
+        state->num_sampler_bindings = desc->num_sampler_bindings;
+    }
+
+    if (desc->num_storage_textures > 0) {
+        state->storage_textures = (SDL_GPUTexture **)SDL_calloc(desc->num_storage_textures, sizeof(*state->storage_textures));
+        if (!state->storage_textures) {
+            SDL_DestroyGPURenderState(state);
+            return NULL;
+        }
+        SDL_memcpy(state->storage_textures, desc->storage_textures, desc->num_storage_textures * sizeof(*state->storage_textures));
+        state->num_storage_textures = desc->num_storage_textures;
+    }
+
+    if (desc->num_storage_buffers > 0) {
+        state->storage_buffers = (SDL_GPUBuffer **)SDL_calloc(desc->num_storage_buffers, sizeof(*state->storage_buffers));
+        if (!state->storage_buffers) {
+            SDL_DestroyGPURenderState(state);
+            return NULL;
+        }
+        SDL_memcpy(state->storage_buffers, desc->storage_buffers, desc->num_storage_buffers * sizeof(*state->storage_buffers));
+        state->num_storage_buffers = desc->num_storage_buffers;
+    }
+
+    return state;
+}
+
+bool SDL_SetGPURenderStateFragmentUniformData(SDL_GPURenderState *state, Uint32 slot_index, const void *data, Uint32 length)
+{
+    if (!state) {
+        return SDL_InvalidParamError("state");
+    }
+
+    if (!FlushRenderCommandsIfGPURenderStateNeeded(state)) {
+        return false;
+    }
+
+    for (int i = 0; i < state->num_uniform_buffers; i++) {
+        SDL_GPURenderStateUniformBuffer *buffer = &state->uniform_buffers[i];
+        if (buffer->slot_index == slot_index) {
+            void *new_data = SDL_realloc(buffer->data, length);
+            if (!new_data) {
+                return false;
+            }
+            SDL_memcpy(new_data, data, length);
+            buffer->data = new_data;
+            buffer->length = length;
+            return true;
+        }
+    }
+
+    SDL_GPURenderStateUniformBuffer *buffers = (SDL_GPURenderStateUniformBuffer *)SDL_realloc(state->uniform_buffers, (state->num_uniform_buffers + 1) * sizeof(*state->uniform_buffers));
+    if (!buffers) {
+        return false;
+    }
+
+    SDL_GPURenderStateUniformBuffer *buffer = &buffers[state->num_uniform_buffers];
+    buffer->slot_index = slot_index;
+    buffer->length = length;
+    buffer->data = SDL_malloc(length);
+    if (!buffer->data) {
+        SDL_free(buffers);
+        return false;
+    }
+    SDL_memcpy(buffer->data, data, length);
+
+    state->uniform_buffers = buffers;
+    ++state->num_uniform_buffers;
+    return true;
+}
+
+bool SDL_SetRenderGPUState(SDL_Renderer *renderer, SDL_GPURenderState *state)
+{
+    CHECK_RENDERER_MAGIC(renderer, false);
+
+    renderer->gpu_render_state = state;
+    return true;
+}
+
+void SDL_DestroyGPURenderState(SDL_GPURenderState *state)
+{
+    if (!state) {
+        return;
+    }
+
+    FlushRenderCommandsIfGPURenderStateNeeded(state);
+
+    if (state->num_uniform_buffers > 0) {
+        for (int i = 0; i < state->num_uniform_buffers; i++) {
+            SDL_free(state->uniform_buffers[i].data);
+        }
+        SDL_free(state->uniform_buffers);
+    }
+    SDL_free(state->sampler_bindings);
+    SDL_free(state->storage_textures);
+    SDL_free(state->storage_buffers);
+    SDL_free(state);
+}

+ 32 - 0
src/render/SDL_sysrender.h

@@ -118,6 +118,36 @@ struct SDL_Texture
     SDL_Texture *next;
 };
 
+// Define the GPU render state structure
+typedef struct SDL_GPURenderStateUniformBuffer
+{
+    Uint32 slot_index;
+    void *data;
+    Uint32 length;
+} SDL_GPURenderStateUniformBuffer;
+
+// Define the GPU render state structure
+struct SDL_GPURenderState
+{
+    SDL_Renderer *renderer;
+
+    Uint32 last_command_generation; // last command queue generation this state was in.
+
+    SDL_GPUShader *fragment_shader;
+
+    int num_sampler_bindings;
+    SDL_GPUTextureSamplerBinding *sampler_bindings;
+
+    int num_storage_textures;
+    SDL_GPUTexture **storage_textures;
+
+    int num_storage_buffers;
+    SDL_GPUBuffer **storage_buffers;
+
+    int num_uniform_buffers;
+    SDL_GPURenderStateUniformBuffer *uniform_buffers;
+};
+
 typedef enum
 {
     SDL_RENDERCMD_NO_OP,
@@ -158,6 +188,7 @@ typedef struct SDL_RenderCommand
             SDL_Texture *texture;
             SDL_ScaleMode texture_scale_mode;
             SDL_TextureAddressMode texture_address_mode;
+            SDL_GPURenderState *gpu_render_state;
         } draw;
         struct
         {
@@ -282,6 +313,7 @@ struct SDL_Renderer
     SDL_FColor color;        /**< Color for drawing operations values */
     SDL_BlendMode blendMode; /**< The drawing blend mode */
     SDL_TextureAddressMode texture_address_mode;
+    SDL_GPURenderState *gpu_render_state;
 
     SDL_RenderCommand *render_commands;
     SDL_RenderCommand *render_commands_tail;

+ 1 - 31
src/render/gpu/SDL_pipeline_gpu.c

@@ -27,40 +27,10 @@
 
 #include "../SDL_sysrender.h"
 
-struct GPU_PipelineCacheKeyStruct
-{
-    Uint64 blend_mode : 28;
-    Uint64 frag_shader : 4;
-    Uint64 vert_shader : 4;
-    Uint64 attachment_format : 6;
-    Uint64 primitive_type : 3;
-};
-
-typedef union GPU_PipelineCacheKeyConverter
-{
-    struct GPU_PipelineCacheKeyStruct as_struct;
-    Uint64 as_uint64;
-} GPU_PipelineCacheKeyConverter;
-
-SDL_COMPILE_TIME_ASSERT(GPU_PipelineCacheKeyConverter_Size, sizeof(GPU_PipelineCacheKeyConverter) <= sizeof(Uint64));
-
 static Uint32 SDLCALL HashPipelineCacheKey(void *userdata, const void *key)
 {
     const GPU_PipelineParameters *params = (const GPU_PipelineParameters *) key;
-    GPU_PipelineCacheKeyConverter cvt;
-    cvt.as_uint64 = 0;
-    cvt.as_struct.blend_mode = params->blend_mode;
-    cvt.as_struct.frag_shader = params->frag_shader;
-    cvt.as_struct.vert_shader = params->vert_shader;
-    cvt.as_struct.attachment_format = params->attachment_format;
-    cvt.as_struct.primitive_type = params->primitive_type;
-
-    // 64-bit uint hash function stolen from taisei (which stole it from somewhere else)
-    Uint64 x = cvt.as_uint64;
-    x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
-    x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
-    x = x ^ (x >> 31);
-    return (Uint32)(x & 0xffffffff);
+    return SDL_murmur3_32(params, sizeof(*params), 0);
 }
 
 static bool SDLCALL MatchPipelineCacheKey(void *userdata, const void *a, const void *b)

+ 1 - 0
src/render/gpu/SDL_pipeline_gpu.h

@@ -33,6 +33,7 @@ typedef struct GPU_PipelineParameters
     GPU_VertexShaderID vert_shader;
     SDL_GPUTextureFormat attachment_format;
     SDL_GPUPrimitiveType primitive_type;
+    SDL_GPUShader *custom_frag_shader;
 } GPU_PipelineParameters;
 
 typedef struct GPU_PipelineCache

+ 29 - 2
src/render/gpu/SDL_render_gpu.c

@@ -541,6 +541,8 @@ static void Draw(
     }
 
     SDL_GPURenderPass *pass = data->state.render_pass;
+    SDL_GPURenderState *custom_state = cmd->data.draw.gpu_render_state;
+    SDL_GPUShader *custom_frag_shader = custom_state ? custom_state->fragment_shader : NULL;
     GPU_VertexShaderID v_shader;
     GPU_FragmentShaderID f_shader;
 
@@ -570,12 +572,18 @@ static void Draw(
         f_shader = FRAG_SHADER_COLOR;
     }
 
+    if (custom_frag_shader) {
+        f_shader = FRAG_SHADER_TEXTURE_CUSTOM;
+        data->shaders.frag_shaders[FRAG_SHADER_TEXTURE_CUSTOM] = custom_frag_shader;
+    }
+
     GPU_PipelineParameters pipe_params;
     SDL_zero(pipe_params);
     pipe_params.blend_mode = cmd->data.draw.blend;
     pipe_params.vert_shader = v_shader;
     pipe_params.frag_shader = f_shader;
     pipe_params.primitive_type = prim;
+    pipe_params.custom_frag_shader = custom_frag_shader;
 
     if (data->state.render_target) {
         pipe_params.attachment_format = ((GPU_TextureData *)data->state.render_target->internal)->format;
@@ -590,15 +598,34 @@ static void Draw(
 
     SDL_BindGPUGraphicsPipeline(pass, pipe);
 
+    Uint32 sampler_slot = 0;
     if (cmd->data.draw.texture) {
         GPU_TextureData *tdata = (GPU_TextureData *)cmd->data.draw.texture->internal;
         SDL_GPUTextureSamplerBinding sampler_bind;
         SDL_zero(sampler_bind);
         sampler_bind.sampler = *SamplerPointer(data, cmd->data.draw.texture_address_mode, cmd->data.draw.texture_scale_mode);
         sampler_bind.texture = tdata->texture;
-        SDL_BindGPUFragmentSamplers(pass, 0, &sampler_bind, 1);
+        SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1);
+    }
+    if (custom_state) {
+        if (custom_state->num_sampler_bindings > 0) {
+            SDL_BindGPUFragmentSamplers(pass, sampler_slot, custom_state->sampler_bindings, custom_state->num_sampler_bindings);
+        }
+        if (custom_state->num_storage_textures > 0) {
+            SDL_BindGPUFragmentStorageTextures(pass, 0, custom_state->storage_textures, custom_state->num_storage_textures);
+        }
+        if (custom_state->num_storage_buffers > 0) {
+            SDL_BindGPUFragmentStorageBuffers(pass, 0, custom_state->storage_buffers, custom_state->num_storage_buffers);
+        }
+        if (custom_state->num_uniform_buffers > 0) {
+            for (int i = 0; i < custom_state->num_uniform_buffers; i++) {
+                SDL_GPURenderStateUniformBuffer *ub = &custom_state->uniform_buffers[i];
+                SDL_PushGPUFragmentUniformData(data->state.command_buffer, ub->slot_index, ub->data, ub->length);
+            }
+        }
+    } else {
+        PushFragmentUniforms(data, cmd);
     }
-    PushFragmentUniforms(data, cmd);
 
     SDL_GPUBufferBinding buffer_bind;
     SDL_zero(buffer_bind);

+ 6 - 0
src/render/gpu/SDL_shaders_gpu.c

@@ -196,6 +196,9 @@ bool GPU_InitShaders(GPU_Shaders *shaders, SDL_GPUDevice *device)
     }
 
     for (int i = 0; i < SDL_arraysize(frag_shader_sources); ++i) {
+        if (i == FRAG_SHADER_TEXTURE_CUSTOM) {
+            continue;
+        }
         shaders->frag_shaders[i] = CompileShader(
             &frag_shader_sources[i], device, SDL_GPU_SHADERSTAGE_FRAGMENT);
         if (shaders->frag_shaders[i] == NULL) {
@@ -215,6 +218,9 @@ void GPU_ReleaseShaders(GPU_Shaders *shaders, SDL_GPUDevice *device)
     }
 
     for (int i = 0; i < SDL_arraysize(shaders->frag_shaders); ++i) {
+        if (i == FRAG_SHADER_TEXTURE_CUSTOM) {
+            continue;
+        }
         SDL_ReleaseGPUShader(device, shaders->frag_shaders[i]);
         shaders->frag_shaders[i] = NULL;
     }

+ 1 - 0
src/render/gpu/SDL_shaders_gpu.h

@@ -44,6 +44,7 @@ typedef enum
     FRAG_SHADER_TEXTURE_RGBA,
     FRAG_SHADER_TEXTURE_RGB_PIXELART,
     FRAG_SHADER_TEXTURE_RGBA_PIXELART,
+    FRAG_SHADER_TEXTURE_CUSTOM,
 
     NUM_FRAG_SHADERS,
 } GPU_FragmentShaderID;

+ 2 - 1
test/CMakeLists.txt

@@ -39,7 +39,7 @@ add_library(sdltests_utils OBJECT
 )
 target_link_libraries(sdltests_utils PRIVATE SDL3::Headers)
 
-file(GLOB RESOURCE_FILES *.bmp *.wav *.hex moose.dat utf8.txt)
+file(GLOB RESOURCE_FILES *.bmp *.wav *.csv *.hex moose.dat utf8.txt)
 
 option(SDLTEST_TRACKMEM "Run tests with --trackmem" OFF)
 
@@ -348,6 +348,7 @@ add_sdl_test_executable(testgl SOURCES testgl.c)
 add_sdl_test_executable(testgles SOURCES testgles.c)
 add_sdl_test_executable(testgpu_simple_clear SOURCES testgpu_simple_clear.c)
 add_sdl_test_executable(testgpu_spinning_cube SOURCES testgpu_spinning_cube.c)
+add_sdl_test_executable(testgpurender_msdf MAIN_CALLBACKS NEEDS_RESOURCES TESTUTILS SOURCES testgpurender_msdf.c)
 if(ANDROID)
     target_link_libraries(testgles PRIVATE GLESv1_CM)
 elseif(IOS OR TVOS)

BIN
test/msdf_font.bmp


+ 95 - 0
test/msdf_font.csv

@@ -0,0 +1,95 @@
+32,0.259765625,0,-0,0,-0,0,256,0,256
+33,0.26416015625,0.04259963723256735,-0.74801901743264665,0.22009567526743265,0.063391442155309036,167.5,44.5,174.5,76.5
+34,0.3984375,0.034401000396196514,-0.74801901743264665,0.36403649960380352,-0.41838351822503961,242.5,175.5,255.5,188.5
+35,0.64599609375,-0.0068815929576070169,-0.74801901743264665,0.65238940545760693,0.038034865293185421,0.5,111.5,26.5,142.5
+36,0.57177734375,0.033055325128763823,-0.79873217115689388,0.54018686237123603,0.08874801901743265,142.5,0.5,162.5,35.5
+37,0.82666015625,0.020303136762083947,-0.77337559429477021,0.80635701948791605,0.038034865293185421,175.5,44.5,206.5,76.5
+38,0.728515625,0.021001510499207562,-0.77337559429477021,0.75634223950079238,0.038034865293185421,214.5,44.5,243.5,76.5
+39,0.21923828125,0.033793550663629157,-0.74801901743264665,0.18593301183637084,-0.41838351822503961,89.5,232.5,95.5,245.5
+40,0.294921875,0.012882577258320127,-0.74801901743264665,0.29180492274167991,0.19017432646592711,62.5,0.5,73.5,37.5
+41,0.294921875,0.0031169522583201267,-0.74801901743264665,0.28203929774167991,0.19017432646592711,74.5,0.5,85.5,37.5
+42,0.55078125,0.0079258648227020154,-0.79873217115689388,0.54041397892729792,-0.26624405705229792,234.5,78.5,255.5,99.5
+43,0.57177734375,0.018668052322702015,-0.62123613312202852,0.55115616642729792,-0.063391442155309036,22.5,232.5,43.5,254.5
+44,0.2587890625,0.011122520676505546,-0.16481774960380352,0.21397513557349446,0.16481774960380349,118.5,232.5,126.5,245.5
+45,0.32177734375,0.0089933513272583213,-0.34231378763866882,0.31327227367274169,-0.19017432646592711,242.5,189.5,254.5,195.5
+46,0.2626953125,0.04259963723256735,-0.13946117274167988,0.22009567526743265,0.063391442155309036,138.5,232.5,145.5,240.5
+47,0.36669921875,-0.019747146146988907,-0.74801901743264665,0.38595808364698891,0.038034865293185421,95.5,143.5,111.5,174.5
+48,0.57177734375,0.019400474197702015,-0.77337559429477021,0.55188858830229792,0.038034865293185421,0.5,78.5,21.5,110.5
+49,0.57177734375,0.055885375396196514,-0.74801901743264665,0.38552087460380352,0.038034865293185421,137.5,143.5,150.5,174.5
+50,0.57177734375,0.016959067947702015,-0.77337559429477021,0.54944718205229792,0.038034865293185421,22.5,78.5,43.5,110.5
+51,0.57177734375,0.012564536697702015,-0.77337559429477021,0.54505265080229792,0.038034865293185421,44.5,78.5,65.5,110.5
+52,0.57177734375,-0.0044912589144215989,-0.74801901743264665,0.57871000891442159,0.038034865293185421,232.5,143.5,255.5,174.5
+53,0.57177734375,0.035740872003763823,-0.74801901743264665,0.54287240924623603,0.038034865293185421,235.5,111.5,255.5,142.5
+54,0.57177734375,0.023795005447702015,-0.77337559429477021,0.55628311955229792,0.038034865293185421,66.5,78.5,87.5,110.5
+55,0.57177734375,0.017203208572702015,-0.74801901743264665,0.54969132267729792,0.038034865293185421,82.5,175.5,103.5,206.5
+56,0.57177734375,0.018912192947702015,-0.77337559429477021,0.55140030705229792,0.038034865293185421,88.5,78.5,109.5,110.5
+57,0.57177734375,0.017935630447702015,-0.77337559429477021,0.55042374455229792,0.038034865293185421,110.5,78.5,131.5,110.5
+58,0.2626953125,0.04259963723256735,-0.59587955625990485,0.22009567526743265,0.063391442155309036,130.5,175.5,137.5,201.5
+59,0.2626953125,-0.0044854552545562608,-0.59587955625990485,0.22372373650455626,0.16481774960380349,104.5,175.5,113.5,205.5
+60,0.57177734375,0.018912192947702015,-0.64659270998415219,0.55140030705229792,-0.08874801901743265,0.5,232.5,21.5,254.5
+61,0.57177734375,0.018912192947702015,-0.51980982567353418,0.55140030705229792,-0.19017432646592711,96.5,232.5,117.5,245.5
+62,0.57177734375,0.018912192947702015,-0.64659270998415219,0.55140030705229792,-0.08874801901743265,44.5,232.5,65.5,254.5
+63,0.431640625,-0.018492394884112522,-0.77337559429477021,0.43792598863411253,0.063391442155309036,22.5,44.5,40.5,77.5
+64,0.896484375,0.030102809899960288,-0.74801901743264665,0.86686984635003961,0.13946117274167988,163.5,0.5,196.5,35.5
+65,0.63232421875,-0.026639959513668827,-0.74801901743264665,0.65798761576366882,0.038034865293185421,23.5,175.5,50.5,206.5
+66,0.64599609375,0.065804217016640215,-0.74801901743264665,0.6236489079833597,0.038034865293185421,0.5,175.5,22.5,206.5
+67,0.6298828125,0.025799202654516594,-0.77337559429477021,0.63435704734548326,0.038034865293185421,132.5,78.5,156.5,110.5
+68,0.7255859375,0.064146304848454794,-0.74801901743264665,0.69806072640154515,0.038034865293185421,189.5,143.5,214.5,174.5
+69,0.5556640625,0.06817752699088743,-0.74801901743264665,0.52459591050911247,0.038034865293185421,170.5,143.5,188.5,174.5
+70,0.51611328125,0.06817752699088743,-0.74801901743264665,0.52459591050911247,0.038034865293185421,151.5,143.5,169.5,174.5
+71,0.72705078125,0.027053953917392983,-0.77337559429477021,0.68632495233260693,0.038034865293185421,157.5,78.5,183.5,110.5
+72,0.7373046875,0.063885140154516601,-0.74801901743264665,0.67244298484548326,0.038034865293185421,112.5,143.5,136.5,174.5
+73,0.279296875,0.063090425663629157,-0.74801901743264665,0.21522988683637084,0.038034865293185421,244.5,44.5,250.5,75.5
+74,0.2685546875,-0.11647790585380349,-0.74801901743264665,0.21315759335380352,0.21553090332805072,48.5,0.5,61.5,38.5
+75,0.6123046875,0.063379834835578408,-0.74801901743264665,0.64658110266442159,0.038034865293185421,45.5,143.5,68.5,174.5
+76,0.52197265625,0.069398230115887444,-0.74801901743264665,0.52581661363411247,0.038034865293185421,26.5,143.5,44.5,174.5
+77,0.8994140625,0.069358378318145758,-0.74801901743264665,0.83005568418185416,0.038034865293185421,51.5,175.5,81.5,206.5
+78,0.7529296875,0.059751773598454787,-0.74801901743264665,0.69366619515154515,0.038034865293185421,0.5,143.5,25.5,174.5
+79,0.77783203125,0.033923939555269372,-0.77337559429477021,0.74390809169473049,0.038034865293185421,184.5,78.5,212.5,110.5
+80,0.6015625,0.070164700128763829,-0.74801901743264665,0.57729623737123603,0.038034865293185421,191.5,111.5,211.5,142.5
+81,0.77783203125,0.033923939555269372,-0.77337559429477021,0.74390809169473049,0.21553090332805072,19.5,0.5,47.5,39.5
+82,0.6171875,0.070198748266640215,-0.74801901743264665,0.6280434392333597,0.038034865293185421,129.5,111.5,151.5,142.5
+83,0.54833984375,0.022313137628763823,-0.77337559429477021,0.52944467487123603,0.038034865293185421,213.5,78.5,233.5,110.5
+84,0.55078125,-0.016942430789421599,-0.74801901743264665,0.56625883703942159,0.038034865293185421,79.5,111.5,102.5,142.5
+85,0.72900390625,0.059734749529516594,-0.74801901743264665,0.66829259422048326,0.038034865293185421,54.5,111.5,78.5,142.5
+86,0.59619140625,-0.031539796082607013,-0.74801901743264665,0.62773120233260693,0.038034865293185421,27.5,111.5,53.5,142.5
+87,0.92333984375,-0.020105038505348741,-0.74801901743264665,0.94344488225534862,0.038034865293185421,152.5,111.5,190.5,142.5
+88,0.57763671875,-0.028382992026545213,-0.74801901743264665,0.60553142952654515,0.038034865293185421,69.5,143.5,94.5,174.5
+89,0.55908203125,-0.037416195151545213,-0.74801901743264665,0.59649822640154515,0.038034865293185421,103.5,111.5,128.5,142.5
+90,0.572265625,0.0069663263916402082,-0.74801901743264665,0.5648110173583597,0.038034865293185421,212.5,111.5,234.5,142.5
+91,0.3271484375,0.052189217883320121,-0.74801901743264665,0.33111156336667991,0.19017432646592711,102.5,0.5,113.5,37.5
+92,0.36669921875,-0.019258864896988907,-0.74801901743264665,0.38644636489698891,0.038034865293185421,215.5,143.5,231.5,174.5
+93,0.3271484375,-0.0037189852416798751,-0.74801901743264665,0.27520336024167991,0.19017432646592711,114.5,0.5,125.5,37.5
+94,0.57177734375,0.0072104670166402082,-0.74801901743264665,0.5650551579833597,-0.24088748019017434,66.5,232.5,88.5,252.5
+95,0.43798828125,-0.034571627996236129,0.063391442155309036,0.47255990924623614,0.19017432646592711,89.5,246.5,109.5,251.5
+96,0.27734375,0.012133131314381934,-0.79873217115689388,0.26569889993561807,-0.57052297939778129,127.5,232.5,137.5,241.5
+97,0.5556640625,0.019122285434825671,-0.57052297939778129,0.50089724581517436,0.038034865293185421,21.5,207.5,40.5,231.5
+98,0.61181640625,0.054556724197702015,-0.79873217115689388,0.58704483830229792,0.038034865293185421,41.5,44.5,62.5,77.5
+99,0.47900390625,0.022767370740887478,-0.57052297939778129,0.47918575425911253,0.038034865293185421,168.5,207.5,186.5,231.5
+100,0.61181640625,0.024527427322702015,-0.79873217115689388,0.55701554142729792,0.038034865293185421,63.5,44.5,84.5,77.5
+101,0.5615234375,0.028904934503763823,-0.57052297939778129,0.53603647174623603,0.038034865293185421,200.5,175.5,220.5,199.5
+102,0.33642578125,-0.017288715828050714,-0.79873217115689388,0.41377309082805075,0.038034865293185421,128.5,44.5,145.5,77.5
+103,0.54296875,-0.022557665164421599,-0.59587955625990485,0.56064360266442159,0.26624405705229792,197.5,0.5,220.5,34.5
+104,0.61328125,0.055027981378763823,-0.79873217115689388,0.56215951862123603,0.038034865293185421,146.5,44.5,166.5,77.5
+105,0.25244140625,0.050883394413629157,-0.77337559429477021,0.20302285558637084,0.038034865293185421,207.5,44.5,213.5,76.5
+106,0.25244140625,-0.091592586172741686,-0.77337559429477021,0.21268633617274166,0.26624405705229792,6.5,0.5,18.5,41.5
+107,0.525390625,0.047947903253763823,-0.79873217115689388,0.55507944049623603,0.038034865293185421,107.5,44.5,127.5,77.5
+108,0.25244140625,0.050150972538629157,-0.79873217115689388,0.20229043371137084,0.038034865293185421,244.5,0.5,250.5,33.5
+109,0.92578125,0.059382660831022144,-0.57052297939778129,0.87079312041897783,0.038034865293185421,60.5,207.5,92.5,231.5
+110,0.61328125,0.055027981378763823,-0.57052297939778129,0.56215951862123603,0.038034865293185421,0.5,207.5,20.5,231.5
+111,0.6015625,0.022347185766640208,-0.57052297939778129,0.5801918767333597,0.038034865293185421,145.5,207.5,167.5,231.5
+112,0.61181640625,0.054556724197702015,-0.57052297939778129,0.58704483830229792,0.26624405705229792,85.5,44.5,106.5,77.5
+113,0.61181640625,0.024039146072702015,-0.57052297939778129,0.55652726017729792,0.26624405705229792,0.5,44.5,21.5,77.5
+114,0.40869140625,0.0493276266590729,-0.57052297939778129,0.42967627959092713,0.038034865293185421,138.5,175.5,153.5,199.5
+115,0.4765625,0.012757605115887478,-0.57052297939778129,0.46917598863411253,0.038034865293185421,41.5,207.5,59.5,231.5
+116,0.3564453125,-0.0156137795909271,-0.69730586370839942,0.36473487334092713,0.038034865293185421,114.5,175.5,129.5,204.5
+117,0.61328125,0.049901028253763823,-0.57052297939778129,0.55703256549623603,0.038034865293185421,221.5,175.5,241.5,199.5
+118,0.49951171875,-0.029166486108359792,-0.57052297939778129,0.5286782048583597,0.038034865293185421,154.5,175.5,176.5,199.5
+119,0.77490234375,-0.01825405791897786,-0.57052297939778129,0.79315640166897772,0.038034865293185421,93.5,207.5,125.5,231.5
+120,0.5234375,-0.017203595483359792,-0.57052297939778129,0.5406410954833597,0.038034865293185421,177.5,175.5,199.5,199.5
+121,0.5009765625,-0.027945782983359792,-0.57052297939778129,0.5298989079833597,0.26624405705229792,221.5,0.5,243.5,33.5
+122,0.46875,0.0059216676158874784,-0.57052297939778129,0.46234005113411253,0.038034865293185421,126.5,207.5,144.5,231.5
+123,0.375,-0.0048715920909271002,-0.74801901743264665,0.37547706084092713,0.19017432646592711,86.5,0.5,101.5,37.5
+124,0.54931640625,0.21077847971969096,-0.79873217115689377,0.33756136403030901,0.29160063391442159,0.5,0.5,5.5,43.5
+125,0.375,1.122040907289984e-05,-0.74801901743264665,0.38035987334092713,0.19017432646592711,126.5,0.5,141.5,37.5
+126,0.57177734375,0.018912192947702015,-0.44374009508716328,0.55140030705229792,-0.24088748019017434,234.5,100.5,255.5,108.5

+ 321 - 0
test/testgpurender_msdf.c

@@ -0,0 +1,321 @@
+/*
+  Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely.
+*/
+
+#define SDL_MAIN_USE_CALLBACKS 1  /* use the callbacks instead of main() */
+#include <SDL3/SDL.h>
+#include <SDL3/SDL_main.h>
+
+#include "testutils.h"
+
+/* This font was created with:
+ * ./msdf-atlas-gen.exe -font OpenSans-VariableFont_wdth,wght.ttf -chars '[32,126]' -type msdf -potr -yorigin top -imageout msdf_font.bmp -csv msdf_font.csv
+ */
+
+/* This is the distance field range in pixels used when generating the font atlas, defaults to 2 */
+#define DISTANCE_FIELD_RANGE 2.0f
+
+/* MSDF shaders */
+#include "testgpurender_msdf.frag.dxil.h"
+#include "testgpurender_msdf.frag.msl.h"
+#include "testgpurender_msdf.frag.spv.h"
+
+typedef struct
+{
+    float distance_field_range;
+    float texture_width;
+    float texture_height;
+    float padding;
+} MSDFShaderUniforms;
+
+static SDL_Window *window = NULL;
+static SDL_Renderer *renderer = NULL;
+static SDL_Texture *font_texture = NULL;
+static SDL_GPUDevice *device = NULL;
+static SDL_GPUShader *shader = NULL;
+static SDL_GPURenderState *render_state = NULL;
+
+typedef struct
+{
+    bool loaded;
+    SDL_FRect src;
+    SDL_FRect dst;
+    float advance;
+} GlyphInfo;
+
+static GlyphInfo glyphs[128];
+
+static bool LoadFontTexture(void)
+{
+    font_texture = LoadTexture(renderer, "msdf_font.bmp", false, NULL, NULL);
+    if (!font_texture) {
+        SDL_Log("Failed to create font texture: %s", SDL_GetError());
+        return false;
+    }
+    SDL_SetTextureBlendMode(font_texture, SDL_BLENDMODE_BLEND);
+
+    /* Set the font color, doesn't need to be done every frame */
+    SDL_SetTextureColorMod(font_texture, 0, 0, 0);
+
+    return true;
+}
+
+static bool LoadFontLayout(void)
+{
+    const char *file = "msdf_font.csv";
+    char *path;
+    int offset = 0, len, codepoint;
+    float src_left, src_top, src_right, src_bottom;
+    float dst_left, dst_top, dst_right, dst_bottom;
+    float advance;
+    char *font_layout;
+
+    path = GetNearbyFilename(file);
+    if (path) {
+        font_layout = (char *)SDL_LoadFile(path, NULL);
+        SDL_free(path);
+    } else {
+        font_layout = (char *)SDL_LoadFile(file, NULL);
+    }
+    if (!font_layout) {
+        SDL_Log("Failed to load font layout: %s", SDL_GetError());
+        return false;
+    }
+
+    while (SDL_sscanf(&font_layout[offset], "%d,%f,%f,%f,%f,%f,%f,%f,%f,%f%n",
+                      &codepoint, &advance,
+                      &dst_left, &dst_top, &dst_right, &dst_bottom,
+                      &src_left, &src_top, &src_right, &src_bottom, &len) == 10) {
+        if (codepoint >= 0 && codepoint < SDL_arraysize(glyphs)) {
+            GlyphInfo *glyph = &glyphs[codepoint];
+            glyph->loaded = true;
+            glyph->src.x = src_left;
+            glyph->src.y = src_top;
+            glyph->src.w = src_right - src_left;
+            glyph->src.h = src_bottom - src_top;
+            glyph->dst.x = dst_left;
+            glyph->dst.y = dst_top;
+            glyph->dst.w = dst_right - dst_left;
+            glyph->dst.h = dst_bottom - dst_top;
+            glyph->advance = advance;
+        }
+        offset += len;
+    }
+    SDL_free(font_layout);
+    return true;
+}
+
+static float MeasureText(const char *text, float font_size)
+{
+    float width = 0.0f;
+
+    while (*text) {
+        GlyphInfo *glyph;
+        Uint32 codepoint = SDL_StepUTF8(&text, NULL);
+        if (codepoint >= SDL_arraysize(glyphs)) {
+            continue;
+        }
+
+        glyph = &glyphs[codepoint];
+        if (!glyph->loaded) {
+            continue;
+        }
+        width += (glyph->advance * font_size);
+    }
+    return width;
+}
+
+static void RenderText(const char *text, float font_size, float x, float y)
+{
+    SDL_FRect dst;
+
+    /* The y coordinate is actually the baseline for the text */
+
+    while (*text) {
+        GlyphInfo *glyph;
+        Uint32 codepoint = SDL_StepUTF8(&text, NULL);
+        if (codepoint >= SDL_arraysize(glyphs)) {
+            continue;
+        }
+
+        glyph = &glyphs[codepoint];
+        if (!glyph->loaded) {
+            continue;
+        }
+
+        dst.x = x + glyph->dst.x * font_size;
+        dst.y = y + glyph->dst.y * font_size;
+        dst.w = glyph->dst.w * font_size;
+        dst.h = glyph->dst.h * font_size;
+        SDL_RenderTexture(renderer, font_texture, &glyph->src, &dst);
+        x += (glyph->advance * font_size);
+    }
+}
+
+static bool InitGPURenderState(void)
+{
+    SDL_GPUShaderFormat formats;
+    SDL_GPUShaderCreateInfo info;
+    SDL_GPURenderStateDesc desc;
+    MSDFShaderUniforms uniforms;
+
+    device = (SDL_GPUDevice *)SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_GPU_DEVICE_POINTER, NULL);
+    if (!device) {
+        SDL_Log("Couldn't get GPU device");
+        return false;
+    }
+
+    formats = SDL_GetGPUShaderFormats(device);
+    if (formats == SDL_GPU_SHADERFORMAT_INVALID) {
+        SDL_Log("Couldn't get supported shader formats: %s", SDL_GetError());
+        return false;
+    }
+
+    SDL_zero(info);
+    if (formats & SDL_GPU_SHADERFORMAT_SPIRV) {
+        info.format = SDL_GPU_SHADERFORMAT_SPIRV;
+        info.code = testgpurender_msdf_frag_spv;
+        info.code_size = testgpurender_msdf_frag_spv_len;
+        info.entrypoint = "main";
+    } else if (formats & SDL_GPU_SHADERFORMAT_DXIL) {
+        info.format = SDL_GPU_SHADERFORMAT_DXIL;
+        info.code = testgpurender_msdf_frag_dxil;
+        info.code_size = testgpurender_msdf_frag_dxil_len;
+        info.entrypoint = "main";
+    } else if (formats & SDL_GPU_SHADERFORMAT_MSL) {
+        info.format = SDL_GPU_SHADERFORMAT_MSL;
+        info.code = testgpurender_msdf_frag_msl;
+        info.code_size = testgpurender_msdf_frag_msl_len;
+        info.entrypoint = "main0";
+    } else {
+        SDL_Log("No supported shader format found");
+        return false;
+    }
+    info.num_samplers = 1;
+    info.num_uniform_buffers = 1;
+    info.stage = SDL_GPU_SHADERSTAGE_FRAGMENT;
+    shader = SDL_CreateGPUShader(device, &info);
+    if (!shader) {
+        SDL_Log("Couldn't create shader: %s", SDL_GetError());
+        return false;
+    }
+
+    SDL_INIT_INTERFACE(&desc);
+    desc.fragment_shader = shader;
+    render_state = SDL_CreateGPURenderState(renderer, &desc);
+    if (!render_state) {
+        SDL_Log("Couldn't create render state: %s", SDL_GetError());
+        return false;
+    }
+
+    SDL_zero(uniforms);
+    uniforms.distance_field_range = DISTANCE_FIELD_RANGE;
+    uniforms.texture_width = (float)font_texture->w;
+    uniforms.texture_height = (float)font_texture->h;
+    if (!SDL_SetGPURenderStateFragmentUniformData(render_state, 0, &uniforms, sizeof(uniforms))) {
+        SDL_Log("Couldn't set uniform data: %s", SDL_GetError());
+        return false;
+    }
+
+    return true;
+}
+
+static void QuitGPURenderState(void)
+{
+    if (render_state) {
+        SDL_DestroyGPURenderState(render_state);
+        render_state = NULL;
+    }
+    if (shader) {
+        SDL_ReleaseGPUShader(device, shader);
+        shader = NULL;
+    }
+}
+
+/* This function runs once at startup. */
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
+{
+    const char *description = "GPU render MSDF example";
+
+    SDL_SetAppMetadata(description, "1.0", "com.example.testgpurender_msdf");
+
+    if (!SDL_Init(SDL_INIT_VIDEO)) {
+        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+
+    window = SDL_CreateWindow(description, 640, 480, 0);
+    if (!window) {
+        SDL_Log("Couldn't create window: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+
+    renderer = SDL_CreateRenderer(window, "gpu");
+    if (!renderer) {
+        SDL_Log("Couldn't create renderer: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+    SDL_SetRenderVSync(renderer, 1);
+
+    if (!LoadFontTexture() || !LoadFontLayout()) {
+        return SDL_APP_FAILURE;
+    }
+
+    if (!InitGPURenderState()) {
+        return SDL_APP_FAILURE;
+    }
+
+    return SDL_APP_CONTINUE;  /* carry on with the program! */
+}
+
+/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
+SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
+{
+    if (event->type == SDL_EVENT_QUIT ||
+        (event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_ESCAPE)) {
+        return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
+    }
+    return SDL_APP_CONTINUE;  /* carry on with the program! */
+}
+
+/* This function runs once per frame, and is the heart of the program. */
+SDL_AppResult SDL_AppIterate(void *appstate)
+{
+    const char *text = "Hello world!";
+    float text_width;
+    float text_height;
+    float x, y;
+    int output_width, output_height;
+
+    SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
+    SDL_RenderClear(renderer);
+
+    text_height = 72.0f;
+    text_width = MeasureText(text, text_height);
+    SDL_GetCurrentRenderOutputSize(renderer, &output_width, &output_height);
+    x = (output_width - text_width) / 2;
+    y = (output_height - text_height) / 2;
+    SDL_SetRenderGPUState(renderer, render_state);
+    RenderText("Hello World!", text_height, x, y);
+    SDL_SetRenderGPUState(renderer, NULL);
+
+    SDL_RenderPresent(renderer);
+
+    return SDL_APP_CONTINUE;  /* carry on with the program! */
+}
+
+/* This function runs once at shutdown. */
+void SDL_AppQuit(void *appstate, SDL_AppResult result)
+{
+    /* SDL will clean up the window/renderer for us. */
+    QuitGPURenderState();
+}
+

+ 399 - 0
test/testgpurender_msdf.frag.dxil.h

@@ -0,0 +1,399 @@
+static const unsigned char testgpurender_msdf_frag_dxil[] = {
+  0x44, 0x58, 0x42, 0x43, 0x2e, 0x49, 0xe7, 0xd0, 0x3a, 0xbb, 0xb2, 0xf2,
+  0x7d, 0x23, 0x3a, 0x6b, 0x9a, 0xa6, 0x80, 0x0a, 0x01, 0x00, 0x00, 0x00,
+  0x88, 0x12, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
+  0x4c, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00,
+  0xf0, 0x01, 0x00, 0x00, 0xa0, 0x09, 0x00, 0x00, 0xbc, 0x09, 0x00, 0x00,
+  0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x54, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x00, 0x00, 0x00,
+  0x4f, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0x00, 0x00,
+  0x50, 0x53, 0x56, 0x30, 0x04, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x13, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52,
+  0x44, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x6d,
+  0x61, 0x69, 0x6e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x00, 0x03, 0x02, 0x00, 0x00,
+  0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x42, 0x00,
+  0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x44, 0x10, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0xa8, 0x07, 0x00, 0x00,
+  0x60, 0x00, 0x00, 0x00, 0xea, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c,
+  0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x90, 0x07, 0x00, 0x00,
+  0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0xe1, 0x01, 0x00, 0x00,
+  0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+  0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39,
+  0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62,
+  0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xc4, 0x10, 0x32, 0x14,
+  0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x62, 0x88, 0x48, 0x90, 0x14, 0x20,
+  0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90,
+  0x11, 0x23, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a,
+  0x04, 0x31, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d,
+  0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x6d, 0x30, 0x86, 0xff,
+  0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x00, 0x49, 0x18, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06,
+  0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+  0x32, 0x22, 0x88, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x23, 0xa4, 0x84,
+  0x04, 0x13, 0x23, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8c, 0x8c,
+  0x0b, 0x84, 0xc4, 0x4c, 0x10, 0x98, 0xc1, 0x08, 0x40, 0x09, 0x00, 0x0a,
+  0x66, 0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x29, 0xc6, 0x40, 0x10,
+  0x44, 0x41, 0x90, 0x51, 0x0c, 0x80, 0x20, 0x88, 0x62, 0x20, 0xe4, 0xa6,
+  0xe1, 0xf2, 0x27, 0xec, 0x21, 0x24, 0x7f, 0x25, 0xa4, 0x95, 0x98, 0xfc,
+  0xe2, 0xb6, 0x51, 0x31, 0x0c, 0xc3, 0x40, 0x50, 0x71, 0xcf, 0x70, 0xf9,
+  0x13, 0xf6, 0x10, 0x92, 0x1f, 0x02, 0xcd, 0xb0, 0x10, 0x28, 0x58, 0x0a,
+  0xa3, 0x10, 0x0c, 0x33, 0x0c, 0xc3, 0x40, 0x10, 0xc4, 0x40, 0x4d, 0x21,
+  0x06, 0x62, 0x18, 0xe8, 0x29, 0xc6, 0x40, 0x0c, 0xc3, 0x30, 0x50, 0x54,
+  0x86, 0x81, 0x18, 0x68, 0x3a, 0x6a, 0xb8, 0xfc, 0x09, 0x7b, 0x08, 0xc9,
+  0xe7, 0x36, 0xaa, 0x58, 0x89, 0xc9, 0x2f, 0x6e, 0x1b, 0x11, 0xc3, 0x30,
+  0x0c, 0x85, 0xa8, 0x08, 0x86, 0x20, 0x6b, 0x8e, 0x20, 0x28, 0x06, 0x43,
+  0x14, 0x04, 0x81, 0x51, 0x36, 0x10, 0x30, 0x8c, 0x40, 0x0c, 0x33, 0xb5,
+  0xc1, 0x38, 0xb0, 0x43, 0x38, 0xcc, 0xc3, 0x3c, 0xb8, 0x01, 0x2d, 0x94,
+  0x03, 0x3e, 0xd0, 0x43, 0x3d, 0xc8, 0x43, 0x39, 0xc8, 0x01, 0x29, 0xf0,
+  0x81, 0x3d, 0x94, 0xc3, 0x38, 0xd0, 0xc3, 0x3b, 0xc8, 0x03, 0x1f, 0x98,
+  0x03, 0x3b, 0xbc, 0x43, 0x38, 0xd0, 0x03, 0x1b, 0x80, 0x01, 0x1d, 0xf8,
+  0x01, 0x18, 0xf8, 0x81, 0x1e, 0xe8, 0x41, 0x3b, 0xa4, 0x03, 0x3c, 0xcc,
+  0xc3, 0x2f, 0xd0, 0x43, 0x3e, 0xc0, 0x43, 0x39, 0xa0, 0x80, 0x98, 0x49,
+  0x0c, 0xc6, 0x81, 0x1d, 0xc2, 0x61, 0x1e, 0xe6, 0xc1, 0x0d, 0x68, 0xa1,
+  0x1c, 0xf0, 0x81, 0x1e, 0xea, 0x41, 0x1e, 0xca, 0x41, 0x0e, 0x48, 0x81,
+  0x0f, 0xec, 0xa1, 0x1c, 0xc6, 0x81, 0x1e, 0xde, 0x41, 0x1e, 0xf8, 0xc0,
+  0x1c, 0xd8, 0xe1, 0x1d, 0xc2, 0x81, 0x1e, 0xd8, 0x00, 0x0c, 0xe8, 0xc0,
+  0x0f, 0xc0, 0xc0, 0x0f, 0x90, 0xc0, 0x75, 0xe4, 0x0d, 0x23, 0x08, 0xc3,
+  0x31, 0x13, 0xf6, 0x10, 0x3f, 0xe7, 0x34, 0x13, 0x71, 0x4d, 0x48, 0x18,
+  0x40, 0x0a, 0x6f, 0x92, 0xa6, 0x88, 0x12, 0x26, 0x9f, 0x05, 0x98, 0x67,
+  0x21, 0x22, 0x76, 0x02, 0x26, 0x02, 0x05, 0x04, 0x8d, 0x89, 0x40, 0x00,
+  0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79,
+  0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e,
+  0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07,
+  0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07,
+  0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e,
+  0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07,
+  0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07,
+  0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07,
+  0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07,
+  0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07,
+  0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07,
+  0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20,
+  0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x34,
+  0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4,
+  0x79, 0x80, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+  0xc8, 0x13, 0x01, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xc0, 0x90, 0x67, 0x02, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x80, 0x21, 0x8f, 0x05, 0x04, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x43, 0x9e, 0x0c, 0x08, 0x80, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xb2, 0x40, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+  0x32, 0x1e, 0x98, 0x18, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47,
+  0xc6, 0x04, 0x43, 0x22, 0x4a, 0x60, 0x04, 0xa0, 0x18, 0x8a, 0xa0, 0x24,
+  0xca, 0xa0, 0x30, 0xca, 0xa1, 0x10, 0x4a, 0xa3, 0x3c, 0xca, 0xa5, 0xc4,
+  0xa8, 0x28, 0x89, 0x11, 0x80, 0x22, 0x28, 0x84, 0x02, 0x21, 0xac, 0x06,
+  0xe8, 0x9b, 0x01, 0xa0, 0x70, 0x06, 0x80, 0xc4, 0x19, 0x00, 0x22, 0x67,
+  0x00, 0xa8, 0x1c, 0x0b, 0x31, 0x88, 0x40, 0x20, 0x10, 0x04, 0x01, 0x00,
+  0x79, 0x18, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90,
+  0x46, 0x02, 0x13, 0xc4, 0x8e, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24,
+  0xc6, 0x05, 0xc7, 0x45, 0xa6, 0x06, 0x46, 0xc6, 0x05, 0x07, 0x04, 0x45,
+  0x8c, 0xe6, 0x26, 0x26, 0x06, 0x67, 0x26, 0xa7, 0x2c, 0x65, 0x43, 0x10,
+  0x4c, 0x10, 0x88, 0x64, 0x82, 0x40, 0x28, 0x1b, 0x84, 0x81, 0xd8, 0x20,
+  0x10, 0x04, 0x05, 0xb8, 0xb9, 0x09, 0x02, 0xb1, 0x6c, 0x18, 0x0e, 0x84,
+  0x98, 0x20, 0x7c, 0x1c, 0x93, 0xba, 0x2f, 0xba, 0x32, 0x3c, 0xba, 0x3a,
+  0xb9, 0xb2, 0x09, 0x02, 0xc1, 0x4c, 0x10, 0x88, 0x66, 0x83, 0x40, 0x34,
+  0x1b, 0x12, 0x42, 0x59, 0x18, 0x62, 0x60, 0x08, 0x67, 0x43, 0xf0, 0x4c,
+  0x10, 0xc4, 0xc0, 0x23, 0x43, 0x97, 0x07, 0x57, 0xf6, 0x35, 0xf4, 0xe6,
+  0x46, 0x57, 0x86, 0x47, 0x37, 0x41, 0x20, 0x9c, 0x09, 0x02, 0xf1, 0x6c,
+  0x40, 0x88, 0x48, 0x9a, 0x88, 0x81, 0x02, 0x36, 0x04, 0xd5, 0x04, 0x81,
+  0x0c, 0x3e, 0x26, 0x75, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72,
+  0x1b, 0x10, 0xe2, 0xc2, 0x18, 0x62, 0x20, 0x80, 0x0d, 0x41, 0xb6, 0x81,
+  0x80, 0x00, 0x4b, 0x9b, 0x20, 0x84, 0x41, 0x47, 0x6e, 0xe8, 0xcd, 0x8d,
+  0xae, 0x0c, 0x8f, 0xee, 0x8b, 0x2c, 0x6d, 0x8e, 0x2e, 0xcc, 0x6d, 0xac,
+  0xec, 0xcb, 0x2c, 0xad, 0x8c, 0x8d, 0xec, 0x4b, 0x2e, 0xcc, 0xed, 0xac,
+  0x6c, 0x82, 0x40, 0x40, 0x13, 0x04, 0x6c, 0xdb, 0x80, 0x20, 0xdd, 0x44,
+  0x78, 0x4d, 0xf3, 0x91, 0x1a, 0x7a, 0x73, 0xa3, 0x2b, 0xc3, 0xa3, 0xfb,
+  0xa2, 0x2b, 0xc3, 0xa3, 0xab, 0x93, 0x2b, 0xfb, 0x9a, 0x4b, 0xd3, 0x2b,
+  0x9b, 0x20, 0x10, 0xd1, 0x04, 0x81, 0x90, 0x36, 0x28, 0x48, 0x18, 0x4c,
+  0x62, 0xe0, 0x35, 0xcd, 0x37, 0x06, 0xcc, 0x86, 0x81, 0x02, 0x03, 0x32,
+  0xd8, 0x30, 0x10, 0x5c, 0x19, 0x4c, 0x10, 0x04, 0x60, 0x03, 0xb0, 0x61,
+  0x20, 0xd0, 0x00, 0x0d, 0x36, 0x04, 0x69, 0xb0, 0x61, 0x18, 0xce, 0x40,
+  0x0d, 0x26, 0x08, 0x65, 0x00, 0x06, 0x1b, 0x02, 0x36, 0x20, 0xd1, 0x16,
+  0x96, 0xe6, 0x46, 0x84, 0xaa, 0x08, 0x6b, 0xe8, 0xe9, 0x49, 0x8a, 0x68,
+  0x82, 0x50, 0x58, 0x13, 0x84, 0xe2, 0xda, 0x10, 0x10, 0x13, 0x84, 0x02,
+  0x9b, 0x20, 0x14, 0xd9, 0x04, 0x81, 0x98, 0x36, 0x08, 0x53, 0x1d, 0x6c,
+  0x58, 0x88, 0x37, 0x80, 0x83, 0x38, 0x90, 0x83, 0x39, 0x18, 0xe8, 0x80,
+  0x88, 0x03, 0x3b, 0xd8, 0x10, 0x0c, 0x1b, 0x84, 0x69, 0xda, 0xb0, 0x0c,
+  0x6f, 0x00, 0x07, 0x71, 0x80, 0x07, 0x73, 0x30, 0xcc, 0xc1, 0x10, 0x07,
+  0x79, 0xb0, 0x41, 0xb8, 0x03, 0x3d, 0x60, 0x32, 0x65, 0xf5, 0x45, 0x15,
+  0x26, 0x77, 0x56, 0x46, 0x37, 0x41, 0x28, 0xb4, 0x0d, 0x0b, 0xc1, 0x07,
+  0x70, 0xd0, 0x07, 0x72, 0x10, 0x07, 0x03, 0x1d, 0x10, 0x71, 0x60, 0x07,
+  0x1b, 0x02, 0x3f, 0xd8, 0x30, 0xec, 0xc1, 0x1f, 0x00, 0x1b, 0x8a, 0x33,
+  0x70, 0x03, 0x50, 0xd8, 0x00, 0x1a, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x73,
+  0x13, 0x04, 0x82, 0x62, 0x91, 0xe6, 0x36, 0x47, 0x37, 0x37, 0x41, 0x20,
+  0x2a, 0x1a, 0x73, 0x69, 0x67, 0x5f, 0x6c, 0x64, 0x34, 0xe6, 0xd2, 0xce,
+  0xbe, 0xe6, 0xe8, 0x88, 0xd0, 0x95, 0xe1, 0x7d, 0xb9, 0xbd, 0xc9, 0xb5,
+  0x6d, 0x50, 0x44, 0x61, 0x14, 0x48, 0xa1, 0x14, 0x4c, 0x01, 0x39, 0x05,
+  0x31, 0x40, 0x85, 0xa1, 0x0a, 0x1b, 0x9b, 0x5d, 0x9b, 0x4b, 0x1a, 0x59,
+  0x99, 0x1b, 0xdd, 0x94, 0x20, 0xa8, 0x42, 0x86, 0xe7, 0x62, 0x57, 0x26,
+  0x37, 0x97, 0xf6, 0xe6, 0x36, 0x25, 0x20, 0x9a, 0x90, 0xe1, 0xb9, 0xd8,
+  0x85, 0xb1, 0xd9, 0x95, 0xc9, 0x4d, 0x09, 0x8a, 0x3a, 0x64, 0x78, 0x2e,
+  0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53,
+  0x02, 0xa4, 0x0c, 0x19, 0x9e, 0x8b, 0x5c, 0xd9, 0xdc, 0x5b, 0x9d, 0xdc,
+  0x58, 0xd9, 0xdc, 0x94, 0x40, 0xab, 0x44, 0x86, 0xe7, 0x42, 0x97, 0x07,
+  0x57, 0x16, 0xe4, 0xe6, 0xf6, 0x46, 0x17, 0x46, 0x97, 0xf6, 0xe6, 0x36,
+  0x37, 0x45, 0x28, 0x03, 0x35, 0xa8, 0x43, 0x86, 0xe7, 0x62, 0x97, 0x56,
+  0x76, 0x97, 0x44, 0x36, 0x45, 0x17, 0x46, 0x57, 0x36, 0x25, 0x60, 0x83,
+  0x3a, 0x64, 0x78, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69,
+  0x6e, 0x74, 0x73, 0x53, 0x02, 0x50, 0xe8, 0x42, 0x86, 0xe7, 0x32, 0xf6,
+  0x56, 0xe7, 0x46, 0x57, 0x26, 0x37, 0x37, 0x25, 0x40, 0x05, 0x00, 0x00,
+  0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c,
+  0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3,
+  0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6,
+  0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e,
+  0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43,
+  0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03,
+  0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48,
+  0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20,
+  0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e,
+  0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d,
+  0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89,
+  0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83,
+  0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68,
+  0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90,
+  0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78,
+  0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98,
+  0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5,
+  0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c,
+  0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c,
+  0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43,
+  0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43,
+  0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82,
+  0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70,
+  0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60,
+  0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4,
+  0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00,
+  0x71, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x46, 0x00, 0x0d, 0x97,
+  0xef, 0x3c, 0x7e, 0x80, 0x34, 0x40, 0x84, 0xf9, 0xc5, 0x6d, 0xdb, 0xc1,
+  0x36, 0x5c, 0xbe, 0xf3, 0xf8, 0x42, 0x40, 0x15, 0x05, 0x11, 0x95, 0x0e,
+  0x30, 0x94, 0x84, 0x01, 0x08, 0x98, 0x5f, 0xdc, 0xb6, 0x21, 0x48, 0xc3,
+  0xe5, 0x3b, 0x8f, 0x2f, 0x44, 0x04, 0x30, 0x11, 0x21, 0xd0, 0x0c, 0x0b,
+  0x61, 0x05, 0xce, 0x70, 0xf9, 0xce, 0xe3, 0x0f, 0xce, 0x64, 0xfb, 0xc5,
+  0x6d, 0x5b, 0xc0, 0x34, 0x5c, 0xbe, 0xf3, 0xf8, 0x8b, 0x03, 0x0c, 0x62,
+  0xf3, 0x50, 0x93, 0x5f, 0xdc, 0xb6, 0x0d, 0x40, 0xc3, 0xe5, 0x3b, 0x8f,
+  0x2f, 0x01, 0xcc, 0xb3, 0x10, 0x7e, 0x71, 0xdb, 0x26, 0x50, 0x0d, 0x97,
+  0xef, 0x3c, 0xbe, 0x34, 0x39, 0x11, 0x81, 0x52, 0xd3, 0x43, 0x4d, 0x7e,
+  0x71, 0xdb, 0x66, 0xf0, 0x0c, 0x97, 0xef, 0x3c, 0x3e, 0xd5, 0x00, 0x11,
+  0xe6, 0x17, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xa0, 0x40, 0x54, 0xe9, 0xac, 0xdc, 0xa5, 0x12,
+  0x84, 0x83, 0x18, 0xdf, 0x37, 0xc0, 0x99, 0x88, 0x44, 0x58, 0x49, 0x4c,
+  0xc4, 0x08, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x31, 0x02, 0x00, 0x00,
+  0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0xac, 0x08, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00,
+  0x28, 0x02, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49,
+  0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19,
+  0x1e, 0x04, 0x8b, 0x62, 0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42,
+  0xc4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x62, 0x88,
+  0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42,
+  0xe4, 0x48, 0x0e, 0x90, 0x11, 0x23, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c,
+  0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x31, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07,
+  0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20,
+  0x6d, 0x30, 0x86, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x00,
+  0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42,
+  0x20, 0x4c, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00,
+  0x54, 0x00, 0x00, 0x00, 0x32, 0x22, 0x88, 0x09, 0x20, 0x64, 0x85, 0x04,
+  0x13, 0x23, 0xa4, 0x84, 0x04, 0x13, 0x23, 0xe3, 0x84, 0xa1, 0x90, 0x14,
+  0x12, 0x4c, 0x8c, 0x8c, 0x0b, 0x84, 0xc4, 0x4c, 0x10, 0x98, 0xc1, 0x08,
+  0x40, 0x09, 0x00, 0x0a, 0x66, 0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00,
+  0x29, 0xc6, 0x40, 0x10, 0x44, 0x41, 0x90, 0x51, 0x0c, 0x80, 0x20, 0x88,
+  0x62, 0x20, 0xe4, 0xa6, 0xe1, 0xf2, 0x27, 0xec, 0x21, 0x24, 0x7f, 0x25,
+  0xa4, 0x95, 0x98, 0xfc, 0xe2, 0xb6, 0x51, 0x31, 0x0c, 0xc3, 0x40, 0x50,
+  0x71, 0xcf, 0x70, 0xf9, 0x13, 0xf6, 0x10, 0x92, 0x1f, 0x02, 0xcd, 0xb0,
+  0x10, 0x28, 0x58, 0x0a, 0xa3, 0x10, 0x0c, 0x33, 0x0c, 0xc3, 0x40, 0x10,
+  0xc4, 0x40, 0x4d, 0x21, 0x06, 0x62, 0x18, 0xe8, 0x29, 0xc6, 0x40, 0x0c,
+  0xc3, 0x30, 0x50, 0x54, 0x86, 0x81, 0x18, 0x68, 0x3a, 0x6a, 0xb8, 0xfc,
+  0x09, 0x7b, 0x08, 0xc9, 0xe7, 0x36, 0xaa, 0x58, 0x89, 0xc9, 0x2f, 0x6e,
+  0x1b, 0x11, 0xc3, 0x30, 0x0c, 0x85, 0xa8, 0x08, 0x86, 0x20, 0x6b, 0x8e,
+  0x20, 0x28, 0x06, 0x43, 0x14, 0x04, 0x81, 0x51, 0x36, 0x10, 0x30, 0x8c,
+  0x40, 0x0c, 0x33, 0xb5, 0xc1, 0x38, 0xb0, 0x43, 0x38, 0xcc, 0xc3, 0x3c,
+  0xb8, 0x01, 0x2d, 0x94, 0x03, 0x3e, 0xd0, 0x43, 0x3d, 0xc8, 0x43, 0x39,
+  0xc8, 0x01, 0x29, 0xf0, 0x81, 0x3d, 0x94, 0xc3, 0x38, 0xd0, 0xc3, 0x3b,
+  0xc8, 0x03, 0x1f, 0x98, 0x03, 0x3b, 0xbc, 0x43, 0x38, 0xd0, 0x03, 0x1b,
+  0x80, 0x01, 0x1d, 0xf8, 0x01, 0x18, 0xf8, 0x81, 0x1e, 0xe8, 0x41, 0x3b,
+  0xa4, 0x03, 0x3c, 0xcc, 0xc3, 0x2f, 0xd0, 0x43, 0x3e, 0xc0, 0x43, 0x39,
+  0xa0, 0x80, 0x98, 0x49, 0x0c, 0xc6, 0x81, 0x1d, 0xc2, 0x61, 0x1e, 0xe6,
+  0xc1, 0x0d, 0x68, 0xa1, 0x1c, 0xf0, 0x81, 0x1e, 0xea, 0x41, 0x1e, 0xca,
+  0x41, 0x0e, 0x48, 0x81, 0x0f, 0xec, 0xa1, 0x1c, 0xc6, 0x81, 0x1e, 0xde,
+  0x41, 0x1e, 0xf8, 0xc0, 0x1c, 0xd8, 0xe1, 0x1d, 0xc2, 0x81, 0x1e, 0xd8,
+  0x00, 0x0c, 0xe8, 0xc0, 0x0f, 0xc0, 0xc0, 0x0f, 0x90, 0xc0, 0x75, 0xe4,
+  0x0d, 0x23, 0x08, 0xc3, 0x31, 0x13, 0xf6, 0x10, 0x3f, 0xe7, 0x34, 0x13,
+  0x71, 0x4d, 0x48, 0x18, 0x40, 0x0a, 0x6f, 0x92, 0xa6, 0x88, 0x12, 0x26,
+  0x9f, 0x05, 0x98, 0x67, 0x21, 0x22, 0x76, 0x02, 0x26, 0x02, 0x05, 0x04,
+  0x8d, 0x89, 0x40, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87,
+  0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50,
+  0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30,
+  0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0,
+  0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20,
+  0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0,
+  0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90,
+  0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10,
+  0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20,
+  0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0,
+  0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60,
+  0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86,
+  0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x18, 0xf2, 0x34, 0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x30, 0xe4, 0x79, 0x80, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x60, 0xc8, 0x13, 0x01, 0x01, 0x10, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xc0, 0x90, 0x67, 0x02, 0x02, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x21, 0x8f, 0x05, 0x04, 0xc0, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x9e, 0x0c, 0x08, 0x80,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x40, 0x00, 0x00,
+  0x0f, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90,
+  0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22, 0x4a, 0x60, 0x04, 0xa0,
+  0x20, 0x8a, 0xa1, 0x08, 0x4a, 0xa2, 0x0c, 0x0a, 0xa3, 0x3c, 0xa8, 0x28,
+  0x89, 0x11, 0x80, 0x22, 0x28, 0x84, 0x02, 0xa1, 0x6f, 0x06, 0x80, 0xc4,
+  0x19, 0x00, 0x22, 0x67, 0x00, 0xa8, 0x1c, 0x0b, 0x31, 0x88, 0x40, 0x20,
+  0x10, 0x04, 0x01, 0x00, 0x79, 0x18, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00,
+  0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, 0x8e, 0x0c, 0x6f, 0xec,
+  0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x05, 0xc7, 0x45, 0xa6, 0x06, 0x46, 0xc6,
+  0x05, 0x07, 0x04, 0x45, 0x8c, 0xe6, 0x26, 0x26, 0x06, 0x67, 0x26, 0xa7,
+  0x2c, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x88, 0x64, 0x82, 0x40, 0x28, 0x1b,
+  0x84, 0x81, 0x98, 0x20, 0x10, 0xcb, 0x06, 0x61, 0x30, 0x28, 0xc0, 0xcd,
+  0x4d, 0x10, 0x08, 0x66, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0xe1, 0xbb, 0x08,
+  0x4c, 0x10, 0x88, 0x66, 0x82, 0x40, 0x38, 0x1b, 0x04, 0xc2, 0xd9, 0x90,
+  0x10, 0x0b, 0xd3, 0x10, 0x43, 0x43, 0x3c, 0x1b, 0x02, 0x68, 0x82, 0x20,
+  0x06, 0xd8, 0x04, 0x81, 0x78, 0x26, 0x08, 0x04, 0xb4, 0x01, 0x21, 0x24,
+  0x66, 0x22, 0x06, 0x0a, 0xd8, 0x10, 0x54, 0x13, 0x04, 0x32, 0xc8, 0x36,
+  0x20, 0xc4, 0xc5, 0x34, 0xc4, 0x40, 0x00, 0x1b, 0x02, 0x6c, 0x03, 0x11,
+  0x01, 0x56, 0x36, 0x41, 0x28, 0x03, 0x6d, 0x43, 0xb0, 0x4d, 0x10, 0x04,
+  0x80, 0x44, 0x5b, 0x58, 0x9a, 0x1b, 0x11, 0xaa, 0x22, 0xac, 0xa1, 0xa7,
+  0x27, 0x29, 0xa2, 0x09, 0x42, 0x21, 0x4d, 0x10, 0x8a, 0x69, 0x43, 0x40,
+  0x4c, 0x10, 0x0a, 0x6a, 0x82, 0x50, 0x54, 0x13, 0x04, 0x22, 0xda, 0x20,
+  0x4c, 0x65, 0xb0, 0x61, 0x21, 0x3e, 0x30, 0x08, 0x03, 0x31, 0x18, 0x83,
+  0x81, 0x0c, 0x88, 0x30, 0x30, 0x83, 0x0d, 0xc1, 0xb0, 0x41, 0x98, 0xa6,
+  0x0d, 0xcb, 0xf0, 0x81, 0x41, 0x18, 0xa0, 0xc1, 0x18, 0x0c, 0x63, 0x30,
+  0x84, 0x41, 0x1a, 0x6c, 0x10, 0xce, 0x40, 0x0d, 0x98, 0x4c, 0x59, 0x7d,
+  0x51, 0x85, 0xc9, 0x9d, 0x95, 0xd1, 0x4d, 0x10, 0x0a, 0x6b, 0xc3, 0x42,
+  0xb0, 0x01, 0x18, 0xb4, 0x81, 0x18, 0x84, 0xc1, 0x40, 0x06, 0x44, 0x18,
+  0x98, 0xc1, 0x86, 0xc0, 0x0d, 0x36, 0x0c, 0x6b, 0xf0, 0x06, 0xc0, 0x86,
+  0xa2, 0xf3, 0xe0, 0x40, 0x03, 0xaa, 0xb0, 0xb1, 0xd9, 0xb5, 0xb9, 0xa4,
+  0x91, 0x95, 0xb9, 0xd1, 0x4d, 0x09, 0x82, 0x2a, 0x64, 0x78, 0x2e, 0x76,
+  0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x02, 0xa2, 0x09, 0x19, 0x9e,
+  0x8b, 0x5d, 0x18, 0x9b, 0x5d, 0x99, 0xdc, 0x94, 0xc0, 0xa8, 0x43, 0x86,
+  0xe7, 0x32, 0x87, 0x16, 0x46, 0x56, 0x26, 0xd7, 0xf4, 0x46, 0x56, 0xc6,
+  0x36, 0x25, 0x48, 0xca, 0x90, 0xe1, 0xb9, 0xc8, 0x95, 0xcd, 0xbd, 0xd5,
+  0xc9, 0x8d, 0x95, 0xcd, 0x4d, 0x09, 0xb2, 0x3a, 0x64, 0x78, 0x2e, 0x76,
+  0x69, 0x65, 0x77, 0x49, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x82,
+  0xad, 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b,
+  0x9a, 0x1b, 0xdd, 0xdc, 0x94, 0x00, 0x0e, 0x00, 0x79, 0x18, 0x00, 0x00,
+  0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66,
+  0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07,
+  0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10,
+  0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce,
+  0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b,
+  0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c,
+  0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07,
+  0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11,
+  0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0,
+  0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8,
+  0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b,
+  0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b,
+  0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87,
+  0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07,
+  0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87,
+  0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81,
+  0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30,
+  0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4,
+  0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca,
+  0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39,
+  0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b,
+  0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b,
+  0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87,
+  0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87,
+  0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40,
+  0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00,
+  0x22, 0x00, 0x00, 0x00, 0x46, 0x00, 0x0d, 0x97, 0xef, 0x3c, 0x7e, 0x80,
+  0x34, 0x40, 0x84, 0xf9, 0xc5, 0x6d, 0xdb, 0xc1, 0x36, 0x5c, 0xbe, 0xf3,
+  0xf8, 0x42, 0x40, 0x15, 0x05, 0x11, 0x95, 0x0e, 0x30, 0x94, 0x84, 0x01,
+  0x08, 0x98, 0x5f, 0xdc, 0xb6, 0x21, 0x48, 0xc3, 0xe5, 0x3b, 0x8f, 0x2f,
+  0x44, 0x04, 0x30, 0x11, 0x21, 0xd0, 0x0c, 0x0b, 0x61, 0x05, 0xce, 0x70,
+  0xf9, 0xce, 0xe3, 0x0f, 0xce, 0x64, 0xfb, 0xc5, 0x6d, 0x5b, 0xc0, 0x34,
+  0x5c, 0xbe, 0xf3, 0xf8, 0x8b, 0x03, 0x0c, 0x62, 0xf3, 0x50, 0x93, 0x5f,
+  0xdc, 0xb6, 0x0d, 0x40, 0xc3, 0xe5, 0x3b, 0x8f, 0x2f, 0x01, 0xcc, 0xb3,
+  0x10, 0x7e, 0x71, 0xdb, 0x26, 0x50, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x34,
+  0x39, 0x11, 0x81, 0x52, 0xd3, 0x43, 0x4d, 0x7e, 0x71, 0xdb, 0x66, 0xf0,
+  0x0c, 0x97, 0xef, 0x3c, 0x3e, 0xd5, 0x00, 0x11, 0xe6, 0x17, 0xb7, 0x6d,
+  0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00,
+  0x86, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00,
+  0x0e, 0x00, 0x00, 0x00, 0x84, 0x8d, 0x00, 0x50, 0x51, 0x02, 0x65, 0x40,
+  0x44, 0xb1, 0x95, 0xdd, 0x0c, 0x40, 0x21, 0x94, 0x51, 0x29, 0x94, 0x5c,
+  0x21, 0x95, 0x69, 0x40, 0xa1, 0x06, 0x14, 0x1e, 0x0d, 0x23, 0x00, 0x63,
+  0x04, 0x20, 0x08, 0x82, 0xf0, 0x2f, 0x8c, 0x11, 0x80, 0x20, 0x08, 0xc2,
+  0xdf, 0x0c, 0xc0, 0x18, 0x01, 0x08, 0x82, 0x20, 0xfe, 0x01, 0x00, 0x00,
+  0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x90, 0x99, 0x81, 0xb2, 0x91, 0x01,
+  0x19, 0x4c, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x90, 0x9d, 0xc1, 0x22,
+  0x95, 0x41, 0x19, 0x50, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x90, 0xa1,
+  0x01, 0xc3, 0x99, 0x81, 0x19, 0x54, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60,
+  0x60, 0xc0, 0x01, 0x84, 0x06, 0x67, 0xe0, 0x45, 0x23, 0x06, 0x09, 0x00,
+  0x82, 0x60, 0x60, 0xc4, 0x41, 0x94, 0x06, 0x68, 0x60, 0x49, 0x23, 0x06,
+  0x09, 0x00, 0x82, 0x60, 0x60, 0xc8, 0x81, 0x94, 0x06, 0x69, 0x00, 0x06,
+  0xd3, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x73, 0x30, 0xa9, 0x81,
+  0x1a, 0x60, 0xd4, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x74, 0x40,
+  0xad, 0xc1, 0x1a, 0x84, 0x41, 0x35, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06,
+  0x46, 0x1d, 0x54, 0x6c, 0xc0, 0x06, 0x99, 0x35, 0x62, 0xf0, 0x00, 0x20,
+  0x08, 0x06, 0x0d, 0x1d, 0x3c, 0x09, 0x62, 0x14, 0xcb, 0xd2, 0x06, 0x6d,
+  0x70, 0x2d, 0xa3, 0x09, 0x01, 0x30, 0x9a, 0x20, 0x04, 0xa3, 0x09, 0x83,
+  0x30, 0x62, 0x60, 0x00, 0x20, 0x08, 0x06, 0x53, 0x1d, 0x54, 0xca, 0x88,
+  0x81, 0x01, 0x80, 0x20, 0x18, 0x4c, 0x76, 0x60, 0x29, 0x23, 0x06, 0x06,
+  0x00, 0x82, 0x60, 0x30, 0xdd, 0x41, 0x1c, 0x08, 0x23, 0x06, 0x06, 0x00,
+  0x82, 0x60, 0x30, 0xe1, 0x81, 0x1c, 0x08, 0x23, 0x06, 0x06, 0x00, 0x82,
+  0x60, 0x30, 0xe5, 0x01, 0xe6, 0x8c, 0x18, 0x18, 0x00, 0x08, 0x82, 0xc1,
+  0xa4, 0x07, 0x99, 0x33, 0x62, 0x60, 0x00, 0x20, 0x08, 0x06, 0xd3, 0x1e,
+  0xd4, 0x81, 0x30, 0x62, 0x60, 0x00, 0x20, 0x08, 0x06, 0x13, 0x1f, 0xd8,
+  0x81, 0x60, 0x82, 0x01, 0x1f, 0x13, 0x0c, 0xf8, 0x18, 0x26, 0xd0, 0xc7,
+  0x32, 0x81, 0x3e, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0x60, 0x81, 0x02,
+  0x1a, 0x5c, 0x7d, 0x30, 0x9a, 0x10, 0x00, 0xa3, 0x09, 0x42, 0x30, 0x9a,
+  0x30, 0x08, 0x36, 0x08, 0xf4, 0x31, 0x42, 0xa0, 0xcf, 0x88, 0x41, 0x02,
+  0x80, 0x20, 0x18, 0x44, 0xa8, 0xf0, 0x06, 0x42, 0x80, 0x1c, 0x16, 0x8c,
+  0x81, 0x7c, 0x46, 0x0c, 0x0e, 0x00, 0x04, 0xc1, 0xe0, 0x59, 0x85, 0x36,
+  0x08, 0xc4, 0x60, 0xc4, 0xe0, 0x00, 0x40, 0x10, 0x0c, 0x1e, 0x56, 0x70,
+  0x03, 0xec, 0x1a, 0x31, 0x38, 0x00, 0x10, 0x04, 0x83, 0xa7, 0x15, 0xd8,
+  0x20, 0xb8, 0x46, 0x0c, 0x0e, 0x00, 0x04, 0xc1, 0xe0, 0x71, 0x85, 0x36,
+  0xd0, 0xb2, 0x11, 0x83, 0x03, 0x00, 0x41, 0x30, 0x78, 0x5e, 0x21, 0x0e,
+  0x02, 0xc1, 0x02, 0x35, 0x80, 0x8f, 0x05, 0x86, 0x7c, 0x2c, 0x58, 0x03,
+  0xf8, 0x8c, 0x18, 0x1c, 0x00, 0x08, 0x82, 0xc1, 0x33, 0x0b, 0x75, 0x10,
+  0xb8, 0xc1, 0x88, 0xc1, 0x01, 0x80, 0x20, 0x18, 0x3c, 0xb4, 0x30, 0x07,
+  0xc1, 0x1a, 0x58, 0x30, 0x06, 0xf2, 0x19, 0x31, 0x48, 0x00, 0x10, 0x04,
+  0x03, 0x04, 0x17, 0xee, 0x00, 0x16, 0x60, 0xe1, 0x14, 0xce, 0x60, 0xc4,
+  0x20, 0x01, 0x40, 0x10, 0x0c, 0x10, 0x5c, 0xb8, 0x03, 0x58, 0x80, 0x05,
+  0x3f, 0x30, 0x83, 0x11, 0x83, 0x04, 0x00, 0x41, 0x30, 0x40, 0x70, 0xe1,
+  0x0e, 0x60, 0x01, 0x16, 0x4c, 0xa1, 0x0c, 0x46, 0x0c, 0x12, 0x00, 0x04,
+  0xc1, 0x00, 0xc1, 0x85, 0x3b, 0x80, 0x05, 0x58, 0xe8, 0x83, 0x00, 0x01,
+  0x00, 0x00, 0x00, 0x00
+};
+static const unsigned int testgpurender_msdf_frag_dxil_len = 4744;

+ 37 - 0
test/testgpurender_msdf.frag.hlsl

@@ -0,0 +1,37 @@
+cbuffer Context : register(b0, space3) {
+    float distance_field_range;
+    float2 texture_size;
+};
+
+Texture2D u_texture : register(t0, space2);
+SamplerState u_sampler : register(s0, space2);
+
+struct PSInput {
+    float4 v_color : COLOR0;
+    float2 v_uv : TEXCOORD0;
+};
+
+struct PSOutput {
+    float4 o_color : SV_Target;
+};
+
+float median(float r, float g, float b) {
+    return max(min(r, g), min(max(r, g), b));
+}
+
+float screenPxRange(float2 texCoord) {
+    float2 unitRange = float2(distance_field_range, distance_field_range)/texture_size;
+    float2 screenTexSize = float2(1.0, 1.0)/fwidth(texCoord);
+    return max(0.5*dot(unitRange, screenTexSize), 1.0);
+}
+
+PSOutput main(PSInput input) {
+    PSOutput output;
+    float3 msd = u_texture.Sample(u_sampler, input.v_uv).rgb;
+    float sd = median(msd.r, msd.g, msd.b);
+    float screenPxDistance = screenPxRange(input.v_uv)*(sd - 0.5);
+    float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
+    output.o_color.rgb = input.v_color.rgb;
+    output.o_color.a = (input.v_color.a * opacity);
+    return output;
+}

+ 97 - 0
test/testgpurender_msdf.frag.msl.h

@@ -0,0 +1,97 @@
+static const unsigned char testgpurender_msdf_frag_msl[] = {
+  0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x6d, 0x65,
+  0x74, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x64, 0x6c, 0x69, 0x62, 0x3e, 0x0a,
+  0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x73, 0x69,
+  0x6d, 0x64, 0x2f, 0x73, 0x69, 0x6d, 0x64, 0x2e, 0x68, 0x3e, 0x0a, 0x0a,
+  0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70,
+  0x61, 0x63, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x3b, 0x0a, 0x0a,
+  0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f,
+  0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x0a, 0x7b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x64, 0x69, 0x73, 0x74,
+  0x61, 0x6e, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x72,
+  0x61, 0x6e, 0x67, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61,
+  0x63, 0x6b, 0x65, 0x64, 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20,
+  0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65,
+  0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61,
+  0x6e, 0x74, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x5f, 0x33,
+  0x35, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72,
+  0x75, 0x63, 0x74, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x30, 0x5f, 0x6f, 0x75,
+  0x74, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61,
+  0x74, 0x34, 0x20, 0x6f, 0x75, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x53,
+  0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x5b, 0x5b, 0x63,
+  0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x7d,
+  0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x6d, 0x61,
+  0x69, 0x6e, 0x30, 0x5f, 0x69, 0x6e, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x69, 0x6e, 0x5f, 0x76,
+  0x61, 0x72, 0x5f, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x30, 0x20, 0x5b, 0x5b,
+  0x75, 0x73, 0x65, 0x72, 0x28, 0x6c, 0x6f, 0x63, 0x6e, 0x30, 0x29, 0x5d,
+  0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x32, 0x20, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58,
+  0x43, 0x4f, 0x4f, 0x52, 0x44, 0x30, 0x20, 0x5b, 0x5b, 0x75, 0x73, 0x65,
+  0x72, 0x28, 0x6c, 0x6f, 0x63, 0x6e, 0x31, 0x29, 0x5d, 0x5d, 0x3b, 0x0a,
+  0x7d, 0x3b, 0x0a, 0x0a, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74,
+  0x20, 0x6d, 0x61, 0x69, 0x6e, 0x30, 0x5f, 0x6f, 0x75, 0x74, 0x20, 0x6d,
+  0x61, 0x69, 0x6e, 0x30, 0x28, 0x6d, 0x61, 0x69, 0x6e, 0x30, 0x5f, 0x69,
+  0x6e, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x5b, 0x73, 0x74, 0x61, 0x67, 0x65,
+  0x5f, 0x69, 0x6e, 0x5d, 0x5d, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
+  0x61, 0x6e, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x6f, 0x6e,
+  0x74, 0x65, 0x78, 0x74, 0x26, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+  0x74, 0x20, 0x5b, 0x5b, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x28, 0x30,
+  0x29, 0x5d, 0x5d, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65,
+  0x32, 0x64, 0x3c, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3e, 0x20, 0x75, 0x5f,
+  0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x5b, 0x5b, 0x74, 0x65,
+  0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x2c, 0x20,
+  0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x20, 0x75, 0x5f, 0x73, 0x61,
+  0x6d, 0x70, 0x6c, 0x65, 0x72, 0x20, 0x5b, 0x5b, 0x73, 0x61, 0x6d, 0x70,
+  0x6c, 0x65, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x29, 0x0a, 0x7b, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x30, 0x5f, 0x6f, 0x75,
+  0x74, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x3b, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x5f,
+  0x34, 0x32, 0x20, 0x3d, 0x20, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x75,
+  0x72, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x28, 0x75, 0x5f,
+  0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x6e, 0x2e,
+  0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f,
+  0x4f, 0x52, 0x44, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66,
+  0x6c, 0x6f, 0x61, 0x74, 0x20, 0x5f, 0x34, 0x33, 0x20, 0x3d, 0x20, 0x5f,
+  0x34, 0x32, 0x2e, 0x78, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c,
+  0x6f, 0x61, 0x74, 0x20, 0x5f, 0x34, 0x34, 0x20, 0x3d, 0x20, 0x5f, 0x34,
+  0x32, 0x2e, 0x79, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x34, 0x20, 0x5f, 0x36, 0x35, 0x20, 0x3d, 0x20, 0x66, 0x6c,
+  0x6f, 0x61, 0x74, 0x34, 0x28, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f, 0x76,
+  0x61, 0x72, 0x5f, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x30, 0x2e, 0x78, 0x2c,
+  0x20, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x43,
+  0x4f, 0x4c, 0x4f, 0x52, 0x30, 0x2e, 0x79, 0x2c, 0x20, 0x69, 0x6e, 0x2e,
+  0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x43, 0x4f, 0x4c, 0x4f, 0x52,
+  0x30, 0x2e, 0x7a, 0x2c, 0x20, 0x5f, 0x33, 0x35, 0x2e, 0x77, 0x29, 0x3b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x36, 0x35, 0x2e, 0x77, 0x20, 0x3d,
+  0x20, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x43,
+  0x4f, 0x4c, 0x4f, 0x52, 0x30, 0x2e, 0x77, 0x20, 0x2a, 0x20, 0x66, 0x61,
+  0x73, 0x74, 0x3a, 0x3a, 0x63, 0x6c, 0x61, 0x6d, 0x70, 0x28, 0x28, 0x70,
+  0x72, 0x65, 0x63, 0x69, 0x73, 0x65, 0x3a, 0x3a, 0x6d, 0x61, 0x78, 0x28,
+  0x30, 0x2e, 0x35, 0x20, 0x2a, 0x20, 0x64, 0x6f, 0x74, 0x28, 0x66, 0x6c,
+  0x6f, 0x61, 0x74, 0x32, 0x28, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
+  0x2e, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x66, 0x69,
+  0x65, 0x6c, 0x64, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x29, 0x20, 0x2f,
+  0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x28, 0x43, 0x6f, 0x6e, 0x74,
+  0x65, 0x78, 0x74, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f,
+  0x73, 0x69, 0x7a, 0x65, 0x29, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x32, 0x28, 0x31, 0x2e, 0x30, 0x29, 0x20, 0x2f, 0x20, 0x66, 0x77, 0x69,
+  0x64, 0x74, 0x68, 0x28, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61,
+  0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x30, 0x29,
+  0x29, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x20, 0x2a, 0x20, 0x28, 0x70,
+  0x72, 0x65, 0x63, 0x69, 0x73, 0x65, 0x3a, 0x3a, 0x6d, 0x61, 0x78, 0x28,
+  0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x65, 0x3a, 0x3a, 0x6d, 0x69, 0x6e,
+  0x28, 0x5f, 0x34, 0x33, 0x2c, 0x20, 0x5f, 0x34, 0x34, 0x29, 0x2c, 0x20,
+  0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x65, 0x3a, 0x3a, 0x6d, 0x69, 0x6e,
+  0x28, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x65, 0x3a, 0x3a, 0x6d, 0x61,
+  0x78, 0x28, 0x5f, 0x34, 0x33, 0x2c, 0x20, 0x5f, 0x34, 0x34, 0x29, 0x2c,
+  0x20, 0x5f, 0x34, 0x32, 0x2e, 0x7a, 0x29, 0x29, 0x20, 0x2d, 0x20, 0x30,
+  0x2e, 0x35, 0x29, 0x29, 0x20, 0x2b, 0x20, 0x30, 0x2e, 0x35, 0x2c, 0x20,
+  0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f, 0x76,
+  0x61, 0x72, 0x5f, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
+  0x20, 0x3d, 0x20, 0x5f, 0x36, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x3b, 0x0a,
+  0x7d, 0x0a, 0x0a
+};
+static const unsigned int testgpurender_msdf_frag_msl_len = 1119;

+ 162 - 0
test/testgpurender_msdf.frag.spv.h

@@ -0,0 +1,162 @@
+static const unsigned char testgpurender_msdf_frag_spv[] = {
+  0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00,
+  0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00,
+  0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x79, 0x70, 0x65,
+  0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00,
+  0x06, 0x00, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, 0x00,
+  0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65,
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x05, 0x00, 0x06, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x32, 0x64, 0x2e,
+  0x69, 0x6d, 0x61, 0x67, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
+  0x09, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72,
+  0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x00, 0x00,
+  0x74, 0x79, 0x70, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72,
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00,
+  0x75, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x2e, 0x76,
+  0x61, 0x72, 0x2e, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x30, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x2e, 0x76,
+  0x61, 0x72, 0x2e, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x30,
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x00,
+  0x6f, 0x75, 0x74, 0x2e, 0x76, 0x61, 0x72, 0x2e, 0x53, 0x56, 0x5f, 0x54,
+  0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x74, 0x79, 0x70, 0x65,
+  0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x64, 0x2e, 0x69, 0x6d, 0x61,
+  0x67, 0x65, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x47, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x22, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
+  0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
+  0x0b, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x47, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x48, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x23, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
+  0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+  0x2b, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x2b, 0x00, 0x04, 0x00,
+  0x0d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x17, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00,
+  0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+  0x1e, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x15, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x1a, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+  0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+  0x17, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+  0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
+  0x20, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x1a, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 0x00,
+  0x21, 0x00, 0x03, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
+  0x1b, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x20, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
+  0x17, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x3b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00,
+  0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
+  0x1b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x3b, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+  0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x03, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
+  0x36, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
+  0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00,
+  0x25, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+  0x15, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x3d, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
+  0x09, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00,
+  0x28, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x56, 0x00, 0x05, 0x00,
+  0x0c, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
+  0x28, 0x00, 0x00, 0x00, 0x57, 0x00, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00,
+  0x2a, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x2b, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x51, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+  0x2a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x2e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
+  0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x50, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00,
+  0x2d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x31, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+  0x2e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x0f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x33, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00,
+  0x15, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
+  0x33, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00,
+  0x35, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+  0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
+  0x35, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00,
+  0x37, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
+  0xd1, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+  0x26, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00,
+  0x39, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+  0x94, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
+  0x37, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+  0x3a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+  0x3b, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00,
+  0x11, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x3e, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00,
+  0x81, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
+  0x3e, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x2b, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+  0x13, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x09, 0x00, 0x1a, 0x00, 0x00, 0x00,
+  0x41, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x22, 0x00, 0x00, 0x00,
+  0x42, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+  0x3d, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,
+  0x42, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x44, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+  0x52, 0x00, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
+  0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x3e, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
+  0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00
+};
+static const unsigned int testgpurender_msdf_frag_spv_len = 1904;