-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #153 from floooh/customresolve-sample
New sample: customresolve-sapp
- Loading branch information
Showing
6 changed files
with
375 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
//------------------------------------------------------------------------------ | ||
// customresolve-sapp.c | ||
// | ||
// Demonstrate custom MSAA resolve in a render pass which reads individual | ||
// MSAA samples in the fragment shader. | ||
//------------------------------------------------------------------------------ | ||
#include "sokol_app.h" | ||
#include "sokol_gfx.h" | ||
#include "sokol_log.h" | ||
#include "sokol_glue.h" | ||
#define SOKOL_IMGUI_IMPL | ||
#define SOKOL_GFX_IMGUI_IMPL | ||
#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS | ||
#include "cimgui/cimgui.h" | ||
#include "sokol_imgui.h" | ||
#include "sokol_gfx_imgui.h" | ||
#include "customresolve-sapp.glsl.h" | ||
|
||
#define WIDTH (160) | ||
#define HEIGHT (120) | ||
|
||
static struct { | ||
struct { | ||
sg_image img; | ||
sg_pipeline pip; | ||
sg_attachments atts; | ||
sg_pass_action action; | ||
} msaa; | ||
struct { | ||
sg_image img; | ||
sg_pipeline pip; | ||
sg_attachments atts; | ||
sg_pass_action action; | ||
sg_bindings bind; | ||
fs_params_t fs_params; | ||
} resolve; | ||
struct { | ||
sg_pipeline pip; | ||
sg_pass_action action; | ||
sg_bindings bind; | ||
} display; | ||
struct { | ||
sgimgui_t sgimgui; | ||
} ui; | ||
sg_sampler smp; // a common non-filtering sampler | ||
} state; | ||
|
||
const fs_params_t default_weights = { | ||
.weight0 = 0.25f, | ||
.weight1 = 0.25f, | ||
.weight2 = 0.25f, | ||
.weight3 = 0.25f, | ||
}; | ||
|
||
static void draw_fallback(void); | ||
static void draw_ui(void); | ||
|
||
static void init(void) { | ||
sg_setup(&(sg_desc){ | ||
.environment = sglue_environment(), | ||
.logger.func = slog_func, | ||
}); | ||
simgui_setup(&(simgui_desc_t){ .logger.func = slog_func }); | ||
sgimgui_init(&state.ui.sgimgui, &(sgimgui_desc_t){0}); | ||
|
||
// catch WebGL2/GLES3 | ||
if (!sg_query_features().msaa_image_bindings) { | ||
return; | ||
} | ||
|
||
// common objects | ||
state.smp = sg_make_sampler(&(sg_sampler_desc){ | ||
.min_filter = SG_FILTER_NEAREST, | ||
.mag_filter = SG_FILTER_NEAREST, | ||
}); | ||
|
||
// msaa-render-pass objects | ||
state.msaa.img = sg_make_image(&(sg_image_desc){ | ||
.render_target = true, | ||
.width = WIDTH, | ||
.height = HEIGHT, | ||
.pixel_format = SG_PIXELFORMAT_RGBA8, | ||
.sample_count = 4, | ||
.label = "msaa image", | ||
}); | ||
state.msaa.pip = sg_make_pipeline(&(sg_pipeline_desc){ | ||
.shader = sg_make_shader(msaa_shader_desc(sg_query_backend())), | ||
.sample_count = 4, | ||
.depth.pixel_format = SG_PIXELFORMAT_NONE, | ||
.colors[0].pixel_format = SG_PIXELFORMAT_RGBA8, | ||
.label = "msaa pipeline", | ||
}); | ||
state.msaa.atts = sg_make_attachments(&(sg_attachments_desc){ | ||
.colors[0].image = state.msaa.img, | ||
.label = "msaa pass attachments", | ||
}); | ||
state.msaa.action = (sg_pass_action){ | ||
.colors[0] = { | ||
.load_action = SG_LOADACTION_CLEAR, | ||
.store_action = SG_STOREACTION_STORE, | ||
.clear_value = { 0, 0, 0, 1 }, | ||
}, | ||
}; | ||
|
||
// resolve-render-pass objects | ||
state.resolve.img = sg_make_image(&(sg_image_desc){ | ||
.render_target = true, | ||
.width = WIDTH, | ||
.height = HEIGHT, | ||
.pixel_format = SG_PIXELFORMAT_RGBA8, | ||
.sample_count = 1, | ||
.label = "resolve image", | ||
}); | ||
state.resolve.pip = sg_make_pipeline(&(sg_pipeline_desc){ | ||
.shader = sg_make_shader(resolve_shader_desc(sg_query_backend())), | ||
.sample_count = 1, | ||
.depth.pixel_format = SG_PIXELFORMAT_NONE, | ||
.colors[0].pixel_format = SG_PIXELFORMAT_RGBA8, | ||
.label = "resolve pipeline", | ||
}); | ||
state.resolve.atts = sg_make_attachments(&(sg_attachments_desc){ | ||
.colors[0].image = state.resolve.img, | ||
.label = "resolve pass attachments", | ||
}); | ||
state.resolve.action = (sg_pass_action){ | ||
.colors[0] = { | ||
.load_action = SG_LOADACTION_DONTCARE, | ||
.store_action = SG_STOREACTION_STORE | ||
}, | ||
}; | ||
state.resolve.bind = (sg_bindings){ | ||
.images[IMG_texms] = state.msaa.img, | ||
.samplers[SMP_smp] = state.smp, | ||
}; | ||
state.resolve.fs_params = default_weights; | ||
|
||
// swapchain-render-pass objects | ||
state.display.pip = sg_make_pipeline(&(sg_pipeline_desc){ | ||
.shader = sg_make_shader(display_shader_desc(sg_query_backend())), | ||
.label = "display pipeline", | ||
}); | ||
state.display.action = (sg_pass_action){ | ||
.colors[0] = { .load_action = SG_LOADACTION_DONTCARE } | ||
}; | ||
state.display.bind = (sg_bindings){ | ||
.images[IMG_tex] = state.resolve.img, | ||
.samplers[SMP_smp] = state.smp, | ||
}; | ||
} | ||
|
||
static void frame(void) { | ||
draw_ui(); | ||
if (!sg_query_features().msaa_image_bindings) { | ||
draw_fallback(); | ||
return; | ||
} | ||
|
||
// draw a triangle into an msaa render target | ||
sg_begin_pass(&(sg_pass){ .action = state.msaa.action, .attachments = state.msaa.atts }); | ||
sg_apply_pipeline(state.msaa.pip); | ||
sg_draw(0, 3, 1); | ||
sg_end_pass(); | ||
|
||
// custom resolve pass (via a 'fullscreen triangle') | ||
sg_begin_pass(&(sg_pass){ .action = state.resolve.action, .attachments = state.resolve.atts }); | ||
sg_apply_pipeline(state.resolve.pip); | ||
sg_apply_bindings(&state.resolve.bind); | ||
sg_apply_uniforms(UB_fs_params, &SG_RANGE(state.resolve.fs_params)); | ||
sg_draw(0, 3, 1); | ||
sg_end_pass(); | ||
|
||
// the final swapchain pass (also via a 'fullscreen triangle') | ||
sg_begin_pass(&(sg_pass){ .action = state.display.action, .swapchain = sglue_swapchain() }); | ||
sg_apply_pipeline(state.display.pip); | ||
sg_apply_bindings(&state.display.bind); | ||
sg_draw(0, 3, 1); | ||
simgui_render(); | ||
sg_end_pass(); | ||
sg_commit(); | ||
} | ||
|
||
static void cleanup(void) { | ||
sgimgui_discard(&state.ui.sgimgui); | ||
simgui_shutdown(); | ||
sg_shutdown(); | ||
} | ||
|
||
static void draw_ui(void) { | ||
simgui_new_frame(&(simgui_frame_desc_t){ | ||
.width = sapp_width(), | ||
.height = sapp_height(), | ||
.dpi_scale = sapp_dpi_scale(), | ||
.delta_time = sapp_frame_duration(), | ||
}); | ||
if (igBeginMainMenuBar()) { | ||
sgimgui_draw_menu(&state.ui.sgimgui, "sokol-gfx"); | ||
igEndMainMenuBar(); | ||
} | ||
sgimgui_draw(&state.ui.sgimgui); | ||
|
||
igSetNextWindowPos((ImVec2){10, 20}, ImGuiCond_Once, (ImVec2){0,0}); | ||
if (igBegin("#window", 0, ImGuiWindowFlags_NoDecoration|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoBackground)) { | ||
if (sg_query_features().msaa_image_bindings) { | ||
igText("Sample Weights:"); | ||
igSliderFloat("0", &state.resolve.fs_params.weight0, 0.0f, 1.0f, "%.2f", 0); | ||
igSliderFloat("1", &state.resolve.fs_params.weight1, 0.0f, 1.0f, "%.2f", 0); | ||
igSliderFloat("2", &state.resolve.fs_params.weight2, 0.0f, 1.0f, "%.2f", 0); | ||
igSliderFloat("3", &state.resolve.fs_params.weight3, 0.0f, 1.0f, "%.2f", 0); | ||
igCheckboxFlags_IntPtr("show complex pixels", &state.resolve.fs_params.coverage, 1); | ||
if (igButton("Reset", (ImVec2){0,0})) { | ||
state.resolve.fs_params = default_weights; | ||
} | ||
} else { | ||
igText("MSAA TEXTURES NOT SUPPORTED ON WEBGL2/GLES3/macOS+GL"); | ||
} | ||
} | ||
igEnd(); | ||
} | ||
|
||
static void draw_fallback(void) { | ||
sg_begin_pass(&(sg_pass){ | ||
.action = { | ||
.colors[0] = { .load_action = SG_LOADACTION_CLEAR, .clear_value = { 0.5f, 0, 0, 1} }, | ||
}, | ||
.swapchain = sglue_swapchain(), | ||
}); | ||
simgui_render(); | ||
sg_end_pass(); | ||
sg_commit(); | ||
} | ||
|
||
static void input(const sapp_event* ev) { | ||
simgui_handle_event(ev); | ||
} | ||
|
||
sapp_desc sokol_main(int argc, char* argv[]) { | ||
(void)argc; (void)argv; | ||
return (sapp_desc){ | ||
.init_cb = init, | ||
.frame_cb = frame, | ||
.cleanup_cb = cleanup, | ||
.event_cb = input, | ||
.width = 640, | ||
.height = 480, | ||
.sample_count = 1, | ||
.window_title = "customresolve-sapp.c", | ||
.icon.sokol_default = true, | ||
.logger.func = slog_func, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// triangle shader which renders into an msaa render target | ||
@vs triangle_vs | ||
|
||
const vec4 colors[3] = { | ||
vec4(1, 1, 0, 1), | ||
vec4(0, 1, 1, 1), | ||
vec4(1, 0, 1, 1), | ||
}; | ||
const vec3 positions[3] = { | ||
vec3(0.0, 0.6, 0.0), | ||
vec3(0.5, -0.6, 0.0), | ||
vec3(-0.5, -0.4, 0.0), | ||
}; | ||
|
||
out vec4 color; | ||
|
||
void main() { | ||
gl_Position = vec4(positions[gl_VertexIndex], 1.0); | ||
color = colors[gl_VertexIndex]; | ||
} | ||
@end | ||
|
||
@fs triangle_fs | ||
in vec4 color; | ||
out vec4 frag_color; | ||
|
||
void main() { | ||
float a = 0; | ||
if ((gl_SampleMaskIn[0] & 15) == 15) { | ||
a = 1; | ||
} | ||
frag_color = vec4(color.xyz, a); | ||
} | ||
@end | ||
|
||
@program msaa triangle_vs triangle_fs | ||
|
||
@block fullscreen_triangle | ||
const vec3 positions[3] = { | ||
vec3(-1.0, -1.0, 0.0), | ||
vec3(3.0, -1.0, 0.0), | ||
vec3(-1.0, 3.0, 0.0), | ||
}; | ||
@end | ||
|
||
// custom resolve shader | ||
@vs resolve_vs | ||
@include_block fullscreen_triangle | ||
|
||
void main() { | ||
gl_Position = vec4(positions[gl_VertexIndex], 1); | ||
} | ||
@end | ||
|
||
@fs resolve_fs | ||
layout(binding=0) uniform texture2DMS texms; | ||
layout(binding=0) uniform sampler smp; | ||
layout(binding=0) uniform fs_params { | ||
float weight0; | ||
float weight1; | ||
float weight2; | ||
float weight3; | ||
int coverage; | ||
}; | ||
|
||
out vec4 frag_color; | ||
|
||
void main() { | ||
ivec2 uv = ivec2(gl_FragCoord.xy); | ||
vec4 s0 = texelFetch(sampler2DMS(texms, smp), uv, 0); | ||
vec4 s1 = texelFetch(sampler2DMS(texms, smp), uv, 1); | ||
vec4 s2 = texelFetch(sampler2DMS(texms, smp), uv, 2); | ||
vec4 s3 = texelFetch(sampler2DMS(texms, smp), uv, 3); | ||
if (coverage != 0) { | ||
if ((s0.w + s1.w + s2.w + s3.w) < 4) { | ||
// complex pixel | ||
frag_color = vec4(1, 0, 0, 1); | ||
} else { | ||
// simple pixel | ||
frag_color = vec4(0, 0, 0, 0); | ||
} | ||
} else { | ||
frag_color = vec4(s0.xyz*weight0 + s1.xyz*weight1 + s2.xyz*weight2 + s3.xyz*weight3, 1); | ||
} | ||
} | ||
@end | ||
|
||
@program resolve resolve_vs resolve_fs | ||
|
||
// the final display pass shader which renders the custom-resolved texture to the display | ||
@vs display_vs | ||
@glsl_options flip_vert_y | ||
@include_block fullscreen_triangle | ||
|
||
out vec2 uv; | ||
|
||
void main() { | ||
const vec4 pos = vec4(positions[gl_VertexIndex], 1); | ||
gl_Position = pos; | ||
uv = (pos.xy + 1.0) * 0.5; | ||
} | ||
@end | ||
|
||
@fs display_fs | ||
layout(binding=0) uniform texture2D tex; | ||
layout(binding=0) uniform sampler smp; | ||
|
||
in vec2 uv; | ||
out vec4 frag_color; | ||
|
||
void main() { | ||
frag_color = texture(sampler2D(tex, smp), uv); | ||
} | ||
@end | ||
|
||
@program display display_vs display_fs |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.