From 2aee105b43f77ef0a84e7d9c5acab29a9ca0d7b5 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 13 Mar 2025 16:41:58 -0700 Subject: [PATCH] Added support for custom shaders with the GPU renderer Added an example of MSDF font rendering with the SDL 2D renderer --- include/SDL3/SDL_render.h | 112 ++++++++ src/dynapi/SDL_dynapi.sym | 4 + src/dynapi/SDL_dynapi_overrides.h | 4 + src/dynapi/SDL_dynapi_procs.h | 4 + src/render/SDL_render.c | 153 +++++++++++ src/render/SDL_sysrender.h | 32 +++ src/render/gpu/SDL_pipeline_gpu.c | 32 +-- src/render/gpu/SDL_pipeline_gpu.h | 1 + src/render/gpu/SDL_render_gpu.c | 31 ++- src/render/gpu/SDL_shaders_gpu.c | 6 + src/render/gpu/SDL_shaders_gpu.h | 1 + test/CMakeLists.txt | 3 +- test/msdf_font.bmp | Bin 0 -> 196662 bytes test/msdf_font.csv | 95 +++++++ test/testgpurender_msdf.c | 321 ++++++++++++++++++++++ test/testgpurender_msdf.frag.dxil.h | 399 ++++++++++++++++++++++++++++ test/testgpurender_msdf.frag.hlsl | 37 +++ test/testgpurender_msdf.frag.msl.h | 97 +++++++ test/testgpurender_msdf.frag.spv.h | 162 +++++++++++ 19 files changed, 1460 insertions(+), 34 deletions(-) create mode 100755 test/msdf_font.bmp create mode 100755 test/msdf_font.csv create mode 100644 test/testgpurender_msdf.c create mode 100644 test/testgpurender_msdf.frag.dxil.h create mode 100644 test/testgpurender_msdf.frag.hlsl create mode 100644 test/testgpurender_msdf.frag.msl.h create mode 100644 test/testgpurender_msdf.frag.spv.h diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h index 432cacfc4d..242556c127 100644 --- a/include/SDL3/SDL_render.h +++ b/include/SDL3/SDL_render.h @@ -59,6 +59,7 @@ #include #include #include +#include #include /* 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 } diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index ecf08a7d93..d40edd2320 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/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: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 2b35173adc..31f8229eaf 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/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 diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 6ea49ff7c9..c87a014dfb 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/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),) diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index a03796a4e6..8622e3a1af 100644 --- a/src/render/SDL_render.c +++ b/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); +} diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 58692388ff..2e6cc76cde 100644 --- a/src/render/SDL_sysrender.h +++ b/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; diff --git a/src/render/gpu/SDL_pipeline_gpu.c b/src/render/gpu/SDL_pipeline_gpu.c index 078337401b..31da279777 100644 --- a/src/render/gpu/SDL_pipeline_gpu.c +++ b/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) diff --git a/src/render/gpu/SDL_pipeline_gpu.h b/src/render/gpu/SDL_pipeline_gpu.h index c3fc39bc69..96e7bd9433 100644 --- a/src/render/gpu/SDL_pipeline_gpu.h +++ b/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 diff --git a/src/render/gpu/SDL_render_gpu.c b/src/render/gpu/SDL_render_gpu.c index d7604f9290..da28b7e55b 100644 --- a/src/render/gpu/SDL_render_gpu.c +++ b/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); diff --git a/src/render/gpu/SDL_shaders_gpu.c b/src/render/gpu/SDL_shaders_gpu.c index 04e06f69db..f09a40e468 100644 --- a/src/render/gpu/SDL_shaders_gpu.c +++ b/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; } diff --git a/src/render/gpu/SDL_shaders_gpu.h b/src/render/gpu/SDL_shaders_gpu.h index d3190fa227..9dc03b6efa 100644 --- a/src/render/gpu/SDL_shaders_gpu.h +++ b/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; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3be04e215e..efbea0c485 100644 --- a/test/CMakeLists.txt +++ b/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) diff --git a/test/msdf_font.bmp b/test/msdf_font.bmp new file mode 100755 index 0000000000000000000000000000000000000000..43d7b72709cb41d0a1d487a2aa966dd0e4c8598e GIT binary patch literal 196662 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őnv|1)RM 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 literal 0 HcmV?d00001 diff --git a/test/msdf_font.csv b/test/msdf_font.csv new file mode 100755 index 0000000000..28fa0d63c6 --- /dev/null +++ b/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 diff --git a/test/testgpurender_msdf.c b/test/testgpurender_msdf.c new file mode 100644 index 0000000000..af25b986bd --- /dev/null +++ b/test/testgpurender_msdf.c @@ -0,0 +1,321 @@ +/* + Copyright (C) 1997-2025 Sam Lantinga + + 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 +#include + +#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(); +} + diff --git a/test/testgpurender_msdf.frag.dxil.h b/test/testgpurender_msdf.frag.dxil.h new file mode 100644 index 0000000000..6a3037a702 --- /dev/null +++ b/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; diff --git a/test/testgpurender_msdf.frag.hlsl b/test/testgpurender_msdf.frag.hlsl new file mode 100644 index 0000000000..2d852fbfcc --- /dev/null +++ b/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; +} diff --git a/test/testgpurender_msdf.frag.msl.h b/test/testgpurender_msdf.frag.msl.h new file mode 100644 index 0000000000..6fc854f66a --- /dev/null +++ b/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; diff --git a/test/testgpurender_msdf.frag.spv.h b/test/testgpurender_msdf.frag.spv.h new file mode 100644 index 0000000000..1df67336fb --- /dev/null +++ b/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;