Преглед на файлове

Added support for custom shaders with the GPU renderer

Added an example of MSDF font rendering with the SDL 2D renderer
Sam Lantinga преди 11 месеца
родител
ревизия
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;