diff --git a/build.zig b/build.zig index 49fed95..93f48bc 100644 --- a/build.zig +++ b/build.zig @@ -168,6 +168,7 @@ pub fn buildLibSokol(b: *Build, options: LibSokolOptions) !*CompileStep { csrc_root ++ "sokol_gl.c", csrc_root ++ "sokol_debugtext.c", csrc_root ++ "sokol_shape.c", + csrc_root ++ "sokol_glue.c", }; for (csources) |csrc| { lib.addCSourceFile(.{ diff --git a/src/examples/blend.d b/src/examples/blend.d index 736654a..ebb0f99 100644 --- a/src/examples/blend.d +++ b/src/examples/blend.d @@ -9,7 +9,7 @@ import sg = sokol.gfx; import app = sokol.app; import log = sokol.log; import handmade.math : Mat4, Vec3; -import sgapp = sokol.glue; +import sglue = sokol.glue; import sgutil = sokol.utils : asRange; import shd = shaders.blend; @@ -20,7 +20,7 @@ immutable NUM_BLEND_FACTORS = 15; struct State { - float r; + float r = 0.0f; sg.Pipeline bg_pip; sg.Pipeline[NUM_BLEND_FACTORS][NUM_BLEND_FACTORS] pips; sg.Bindings bind; @@ -41,7 +41,7 @@ void init() @trusted { sg.Desc gfx = { pipeline_pool_size: NUM_BLEND_FACTORS * NUM_BLEND_FACTORS + 1, - context: sgapp.context(), + environment: sglue.environment, logger: {func: &log.func} }; sg.setup(gfx); @@ -108,7 +108,8 @@ void frame() immutable view = Mat4.lookAt(Vec3(0.0, 0.0, 25.0), Vec3.zero(), Vec3.up()); immutable view_proj = Mat4.mul(proj, view); - sg.beginDefaultPass(state.passAction, app.width(), app.height()); + sg.Pass pass = {action: state.passAction, swapchain: sglue.swapchain}; + sg.beginPass(pass); sg.Range r = sgutil.asRange(state.bg_fs_params); sg.applyPipeline(state.bg_pip); diff --git a/src/examples/clear.d b/src/examples/clear.d index cd3bccc..b32907a 100644 --- a/src/examples/clear.d +++ b/src/examples/clear.d @@ -6,7 +6,7 @@ module examples.clear; import sg = sokol.gfx; -import sgapp = sokol.glue; +import sglue = sokol.glue; import sapp = sokol.app; import log = sokol.log; @@ -16,8 +16,10 @@ __gshared sg.PassAction pass_action; void init() { - sg.Desc gfx = {context: sgapp.context(), - logger: {func: &log.slog_func}}; + sg.Desc gfx = { + environment: sglue.environment, + logger: {func: &log.slog_func} + }; sg.setup(gfx); pass_action.colors[0].load_action = sg.LoadAction.Clear; @@ -44,7 +46,8 @@ void frame() { const g = pass_action.colors[0].clear_value.g + 0.01; pass_action.colors[0].clear_value.g = g > 1.0 ? 0.0 : g; - sg.beginDefaultPass(pass_action, sapp.width(), sapp.height()); + sg.Pass pass = {action: pass_action, swapchain: sglue.swapchain}; + sg.beginPass(pass); sg.endPass(); sg.commit(); } diff --git a/src/examples/cube.d b/src/examples/cube.d index 56afc8b..680778e 100644 --- a/src/examples/cube.d +++ b/src/examples/cube.d @@ -9,7 +9,7 @@ import sg = sokol.gfx; import app = sokol.app; import log = sokol.log; import handmade.math : Mat4, Vec3; -import sgapp = sokol.glue; +import sglue = sokol.glue; import shd = shaders.cube; import sgutil = sokol.utils : asRange; @@ -43,7 +43,7 @@ static State state; void init() @trusted { - sg.Desc gfx = {context: sgapp.context(), + sg.Desc gfx = {environment: sglue.environment, logger: {func: &log.func}}; sg.setup(gfx); @@ -120,7 +120,8 @@ void frame() shd.VsParams vsParams = {mvp: computeVsParams(state.rx, state.ry)}; - sg.beginDefaultPass(state.passAction, app.width(), app.height()); + sg.Pass pass = {action: state.passAction, swapchain: sglue.swapchain}; + sg.beginPass(pass); sg.Range r = sgutil.asRange(vsParams); sg.applyPipeline(state.pip); diff --git a/src/examples/debugtext_print.d b/src/examples/debugtext_print.d index 31b28f0..e939c27 100644 --- a/src/examples/debugtext_print.d +++ b/src/examples/debugtext_print.d @@ -39,7 +39,7 @@ struct State void init() { - sg.Desc gfx = {context: sglue.context(), + sg.Desc gfx = {environment: sglue.environment, logger: {func: &log.func}}; sg.setup(gfx); @@ -88,7 +88,8 @@ void frame() print_font(FONT_C64, "C64:\n", 0x79, 0x86, 0xcb); print_font(FONT_ORIC, "Oric Atmos:\n", 0xff, 0x98, 0x00); - sg.beginDefaultPass(state.passAction, sapp.width(), sapp.height()); + sg.Pass pass = {action: state.passAction, swapchain: sglue.swapchain}; + sg.beginPass(pass); sdtx.draw(); sg.endPass(); sg.commit(); diff --git a/src/examples/mrt.d b/src/examples/mrt.d index 2dbd213..a5a4039 100644 --- a/src/examples/mrt.d +++ b/src/examples/mrt.d @@ -15,7 +15,7 @@ import sg = sokol.gfx; import app = sokol.app; import log = sokol.log; import handmade.math : Mat4, Vec3, Vec2, sin, cos; -import sgapp = sokol.glue; +import sglue = sokol.glue; import shd = shaders.mrt; import sgutil = sokol.utils : asRange; @@ -27,8 +27,8 @@ enum OFFSCREEN_SAMPLE_COUNT = 1; struct Offscreen { sg.PassAction pass_action; - sg.PassDesc pass_desc; - sg.Pass pass; + sg.AttachmentsDesc atts_desc; + sg.Attachments atts; sg.Pipeline pip; sg.Bindings bind; } @@ -65,7 +65,7 @@ static State state; void init() @trusted { - sg.Desc gfx = {context: sgapp.context(), + sg.Desc gfx = {environment: sglue.environment, logger: {func: &log.slog_func}}; sg.setup(gfx); @@ -95,7 +95,7 @@ void init() @trusted // setup the offscreen render pass and render target images, // this will also be called when the window resizes - createOffscreenPass(app.width(), app.height()); + createOffscreenAttachments(app.width(), app.height()); float[96] VERTICES = [ // positions brightness @@ -201,7 +201,7 @@ void init() @trusted state.fsq.bind.vertex_buffers[0] = quad_vbuf; foreach (i; [0, 1, 2]) { - state.fsq.bind.fs.images[i] = state.offscreen.pass_desc.color_attachments[i].image; + state.fsq.bind.fs.images[i] = state.offscreen.atts_desc.colors[i].image; } state.fsq.bind.fs.samplers[0] = smp; @@ -233,7 +233,8 @@ void frame() }; // render cube into MRT offscreen render targets - sg.beginPass(state.offscreen.pass, state.offscreen.pass_action); + sg.Pass pass_atts = {action: state.offscreen.pass_action, attachments: state.offscreen.atts}; + sg.beginPass(pass_atts); sg.applyPipeline(state.offscreen.pip); sg.applyBindings(state.offscreen.bind); auto offs_rg = sgutil.asRange(offscreen_params); @@ -247,7 +248,8 @@ void frame() // render fullscreen quad with the composed offscreen-render images, // 3 a small debug view quads at the bottom of the screen - sg.beginDefaultPass(state.dflt.pass_action, app.width(), app.height()); + sg.Pass pass_swap = {action: state.dflt.pass_action, swapchain: sglue.swapchain}; + sg.beginPass(pass_swap); sg.applyPipeline(state.fsq.pip); sg.applyBindings(state.fsq.bind); auto fsq_rg = sgutil.asRange(fsq_params); @@ -257,7 +259,7 @@ void frame() foreach (i; [0, 1, 2]) { sg.applyViewport(i * 100, 0, 100, 100, false); - state.dbg.bind.fs.images[0] = state.offscreen.pass_desc.color_attachments[i].image; + state.dbg.bind.fs.images[0] = state.offscreen.atts_desc.colors[i].image; sg.applyBindings(state.dbg.bind); sg.draw(0, 4, 1); } @@ -269,7 +271,7 @@ void event(const app.Event* ev) { if (ev.type == app.EventType.Resized) { - createOffscreenPass(ev.framebuffer_width, ev.framebuffer_height); + createOffscreenAttachments(ev.framebuffer_width, ev.framebuffer_height); } } @@ -295,15 +297,15 @@ void main() app.run(runner); } -void createOffscreenPass(int width, int height) +void createOffscreenAttachments(int width, int height) { // destroy previous resources (can be called with invalid ids) - sg.destroyPass(state.offscreen.pass); - foreach (att; state.offscreen.pass_desc.color_attachments) + sg.destroyAttachments(state.offscreen.atts); + foreach (att; state.offscreen.atts_desc.colors) { sg.destroyImage(att.image); } - sg.destroyImage(state.offscreen.pass_desc.depth_stencil_attachment.image); + sg.destroyImage(state.offscreen.atts_desc.depth_stencil.image); // create offscreen render target images and pass sg.ImageDesc color_img_desc = { @@ -317,15 +319,15 @@ void createOffscreenPass(int width, int height) foreach (i; [0, 1, 2]) { - state.offscreen.pass_desc.color_attachments[i].image = sg.makeImage(color_img_desc); + state.offscreen.atts_desc.colors[i].image = sg.makeImage(color_img_desc); } - state.offscreen.pass_desc.depth_stencil_attachment.image = sg.makeImage(depth_img_desc); - state.offscreen.pass = sg.makePass(state.offscreen.pass_desc); + state.offscreen.atts_desc.depth_stencil.image = sg.makeImage(depth_img_desc); + state.offscreen.atts = sg.makeAttachments(state.offscreen.atts_desc); // update the fullscreen-quad texture bindings foreach (i; [0, 1, 2]) { - state.fsq.bind.fs.images[i] = state.offscreen.pass_desc.color_attachments[i].image; + state.fsq.bind.fs.images[i] = state.offscreen.atts_desc.colors[i].image; } } diff --git a/src/examples/saudio.d b/src/examples/saudio.d index b704887..08cf9e4 100644 --- a/src/examples/saudio.d +++ b/src/examples/saudio.d @@ -7,7 +7,7 @@ module examples.saudio; import sg = sokol.gfx; import app = sokol.app; import log = sokol.log; -import sgapp = sokol.glue; +import sglue = sokol.glue; import saudio = sokol.audio; extern (C): @@ -34,8 +34,10 @@ static State state; void init() { - sg.Desc gfx = {context: sgapp.context(), - logger: {func: &log.slog_func}}; + sg.Desc gfx = { + environment: sglue.environment, + logger: {func: &log.slog_func} + }; sg.setup(gfx); saudio.Desc audio = {logger: {func: &log.slog_func}}; saudio.setup(audio); @@ -59,7 +61,8 @@ void frame() state.samples[state.sample_pos] = (0 != (state.even_odd & 0x20)) ? 0.1 : -0.1; } - sg.beginDefaultPass(state.pass_action, app.width(), app.height()); + sg.Pass pass = {action: state.pass_action, swapchain: sglue.swapchain}; + sg.beginPass(pass); sg.endPass(); sg.commit(); } diff --git a/src/examples/sgl_context.d b/src/examples/sgl_context.d index 4166aed..e2e397d 100644 --- a/src/examples/sgl_context.d +++ b/src/examples/sgl_context.d @@ -7,7 +7,7 @@ module examples.sgl_context; import sg = sokol.gfx; -import sgapp = sokol.glue; +import sglue = sokol.glue; import sapp = sokol.app; import slog = sokol.log; import sgl = sokol.gl; @@ -19,7 +19,7 @@ extern (C): struct Offscreen { sg.PassAction pass_action; - sg.Pass pass; + sg.Attachments attachments; sg.Image img; sgl.Context sgl_ctx; } @@ -44,7 +44,7 @@ enum offscreen_height = 32; void init() { - sg.Desc gfxd = {context: sgapp.context(), + sg.Desc gfxd = {environment: sglue.environment, logger: {func: &slog.func}}; sg.setup(gfxd); @@ -85,7 +85,7 @@ void init() }; state.offscreen.sgl_ctx = sgl.makeContext(ctd); - // create an offscreen render target texture, pass and pass-action + // create an offscreen render target texture, pass-attachments object and pass-action sg.ImageDesc imgd = { render_target: true, width: offscreen_width, @@ -95,9 +95,9 @@ void init() }; state.offscreen.img = sg.makeImage(imgd); - sg.PassDesc pass_desc; - pass_desc.color_attachments[0].image = state.offscreen.img; - state.offscreen.pass = sg.makePass(pass_desc); + sg.AttachmentsDesc attachmentDesc; + attachmentDesc.colors[0].image = state.offscreen.img; + state.offscreen.attachments = sg.makeAttachments(attachmentDesc); state.offscreen.pass_action.colors[0].load_action = sg.LoadAction.Clear; state.offscreen.pass_action.colors[0].clear_value.r = 0.0; @@ -141,10 +141,16 @@ void frame() draw_cube(); // do the actual offscreen and display rendering in sokol-gfx passes - sg.beginPass(state.offscreen.pass, state.offscreen.pass_action); + sg.Pass pass1 = { + action: state.offscreen.pass_action, attachments: state.offscreen.attachments + }; + sg.beginPass(pass1); sgl.contextDraw(state.offscreen.sgl_ctx); sg.endPass(); - sg.beginDefaultPass(state.display.pass_action, sapp.width(), sapp.height()); + sg.Pass pass2 = { + action: state.display.pass_action, swapchain: sglue.swapchain + }; + sg.beginPass(pass2); sgl.contextDraw(sgl.defaultContext()); sg.endPass(); sg.commit(); diff --git a/src/examples/sgl_points.d b/src/examples/sgl_points.d index a6b5858..72b70be 100644 --- a/src/examples/sgl_points.d +++ b/src/examples/sgl_points.d @@ -9,7 +9,7 @@ module examples.sgl_points; import sg = sokol.gfx; -import sgapp = sokol.glue; +import sglue = sokol.glue; import sapp = sokol.app; import slog = sokol.log; import sgl = sokol.gl; @@ -56,7 +56,7 @@ immutable float[3][16] pallete = [ void init() { - sg.Desc gfxd = {context: sgapp.context(), + sg.Desc gfxd = {environment: sglue.environment, logger: {func: &slog.func}}; sg.setup(gfxd); @@ -88,7 +88,8 @@ void frame() } sgl.end(); - sg.beginDefaultPass(state.pass_action, sapp.width, sapp.height); + sg.Pass pass = {action: state.pass_action, swapchain: sglue.swapchain}; + sg.beginPass(pass); sgl.draw(); sg.endPass(); sg.commit(); diff --git a/src/examples/triangle.d b/src/examples/triangle.d index 41f853c..908e008 100644 --- a/src/examples/triangle.d +++ b/src/examples/triangle.d @@ -8,7 +8,7 @@ module examples.triangle; import sg = sokol.gfx; import sapp = sokol.app; import log = sokol.log; -import sgapp = sokol.glue; +import sglue = sokol.glue; import sgutil = sokol.utils; extern (C): @@ -22,7 +22,7 @@ struct State void init() @trusted { - sg.Desc gfx = {context: sgapp.context(), + sg.Desc gfx = {environment: sglue.environment, logger: {func: &log.slog_func}}; sg.setup(gfx); State state; @@ -51,7 +51,8 @@ void frame() State state; // default pass-action clears to grey sg.PassAction pass_action; - sg.beginDefaultPass(pass_action, sapp.width(), sapp.height()); + sg.Pass pass = {action: pass_action, swapchain: sglue.swapchain}; + sg.beginPass(pass); sg.applyPipeline(state.pip); sg.applyBindings(state.bind); sg.draw(0, 3, 1); diff --git a/src/examples/user_data.d b/src/examples/user_data.d index f16582e..d545fd2 100644 --- a/src/examples/user_data.d +++ b/src/examples/user_data.d @@ -3,7 +3,7 @@ module examples.user_data; import sg = sokol.gfx; import sapp = sokol.app; import log = sokol.log; -import sgapp = sokol.glue; +import sglue = sokol.glue; extern (C): @@ -15,8 +15,10 @@ struct ExampleUserData void init() @safe { - sg.Desc gfx = {context: sgapp.context(), - logger: {func: &log.slog_func}}; + sg.Desc gfx = { + environment: sglue.environment, + logger: {func: &log.slog_func} + }; sg.setup(gfx); } @@ -54,8 +56,9 @@ void frame_userdata(scope void* userdata) @trusted } } - sg.PassAction pass_action = {}; - sg.beginDefaultPass(pass_action, sapp.width(), sapp.height()); + sg.PassAction pass_action; + sg.Pass pass = {action: pass_action, swapchain: sglue.swapchain}; + sg.beginPass(pass); sg.endPass(); sg.commit(); } @@ -80,6 +83,7 @@ void main() sample_count: 4, win32_console_attach: true, icon: {sokol_default: true}, - logger: {func: &log.func}}; - sapp.run(runner); - } + logger: {func: &log.func} + }; + sapp.run(runner); +} diff --git a/src/sokol/app.d b/src/sokol/app.d index 5ba4ca7..f686610 100644 --- a/src/sokol/app.d +++ b/src/sokol/app.d @@ -165,8 +165,8 @@ enum AndroidTooltype { extern(C) struct Touchpoint { ulong identifier = 0; - float pos_x = 0.0; - float pos_y = 0.0; + float pos_x = 0.0f; + float pos_y = 0.0f; AndroidTooltype android_tooltype; bool changed = false; } @@ -192,12 +192,12 @@ struct Event { bool key_repeat = false; uint modifiers = 0; Mousebutton mouse_button; - float mouse_x = 0.0; - float mouse_y = 0.0; - float mouse_dx = 0.0; - float mouse_dy = 0.0; - float scroll_x = 0.0; - float scroll_y = 0.0; + float mouse_x = 0.0f; + float mouse_y = 0.0f; + float mouse_dx = 0.0f; + float mouse_dy = 0.0f; + float scroll_x = 0.0f; + float scroll_y = 0.0f; int num_touches = 0; Touchpoint[8] touches; int window_width = 0; @@ -575,13 +575,17 @@ extern(C) scope const(void)* sapp_metal_get_device() @system @nogc nothrow; scope const(void)* metalGetDevice() @trusted @nogc nothrow { return sapp_metal_get_device(); } -extern(C) scope const(void)* sapp_metal_get_renderpass_descriptor() @system @nogc nothrow; -scope const(void)* metalGetRenderpassDescriptor() @trusted @nogc nothrow { - return sapp_metal_get_renderpass_descriptor(); +extern(C) scope const(void)* sapp_metal_get_current_drawable() @system @nogc nothrow; +scope const(void)* metalGetCurrentDrawable() @trusted @nogc nothrow { + return sapp_metal_get_current_drawable(); } -extern(C) scope const(void)* sapp_metal_get_drawable() @system @nogc nothrow; -scope const(void)* metalGetDrawable() @trusted @nogc nothrow { - return sapp_metal_get_drawable(); +extern(C) scope const(void)* sapp_metal_get_depth_stencil_texture() @system @nogc nothrow; +scope const(void)* metalGetDepthStencilTexture() @trusted @nogc nothrow { + return sapp_metal_get_depth_stencil_texture(); +} +extern(C) scope const(void)* sapp_metal_get_msaa_color_texture() @system @nogc nothrow; +scope const(void)* metalGetMsaaColorTexture() @trusted @nogc nothrow { + return sapp_metal_get_msaa_color_texture(); } extern(C) scope const(void)* sapp_macos_get_window() @system @nogc nothrow; scope const(void)* macosGetWindow() @trusted @nogc nothrow { @@ -603,9 +607,13 @@ extern(C) scope const(void)* sapp_d3d11_get_swap_chain() @system @nogc nothrow; scope const(void)* d3d11GetSwapChain() @trusted @nogc nothrow { return sapp_d3d11_get_swap_chain(); } -extern(C) scope const(void)* sapp_d3d11_get_render_target_view() @system @nogc nothrow; -scope const(void)* d3d11GetRenderTargetView() @trusted @nogc nothrow { - return sapp_d3d11_get_render_target_view(); +extern(C) scope const(void)* sapp_d3d11_get_render_view() @system @nogc nothrow; +scope const(void)* d3d11GetRenderView() @trusted @nogc nothrow { + return sapp_d3d11_get_render_view(); +} +extern(C) scope const(void)* sapp_d3d11_get_resolve_view() @system @nogc nothrow; +scope const(void)* d3d11GetResolveView() @trusted @nogc nothrow { + return sapp_d3d11_get_resolve_view(); } extern(C) scope const(void)* sapp_d3d11_get_depth_stencil_view() @system @nogc nothrow; scope const(void)* d3d11GetDepthStencilView() @trusted @nogc nothrow { @@ -631,6 +639,10 @@ extern(C) scope const(void)* sapp_wgpu_get_depth_stencil_view() @system @nogc no scope const(void)* wgpuGetDepthStencilView() @trusted @nogc nothrow { return sapp_wgpu_get_depth_stencil_view(); } +extern(C) uint sapp_gl_get_framebuffer() @system @nogc nothrow; +uint glGetFramebuffer() @trusted @nogc nothrow { + return sapp_gl_get_framebuffer(); +} extern(C) scope const(void)* sapp_android_get_native_activity() @system @nogc nothrow; scope const(void)* androidGetNativeActivity() @trusted @nogc nothrow { return sapp_android_get_native_activity(); diff --git a/src/sokol/c/sokol_app.h b/src/sokol/c/sokol_app.h index 064a72f..e0c3462 100644 --- a/src/sokol/c/sokol_app.h +++ b/src/sokol/c/sokol_app.h @@ -266,8 +266,9 @@ Return the MSAA sample count of the default framebuffer. const void* sapp_metal_get_device(void) - const void* sapp_metal_get_renderpass_descriptor(void) - const void* sapp_metal_get_drawable(void) + const void* sapp_metal_get_current_drawable(void) + const void* sapp_metal_get_depth_stencil_texture(void) + const void* sapp_metal_get_msaa_color_texture(void) If the Metal backend has been selected, these functions return pointers to various Metal API objects required for rendering, otherwise they return a null pointer. These void pointers are actually @@ -287,14 +288,10 @@ Before being used as Objective-C object, the void* must be converted back with a (ARC) __bridge cast. - const void* sapp_win32_get_hwnd(void) - On Windows, get the window's HWND, otherwise a null pointer. The - HWND has been cast to a void pointer in order to be tunneled - through code which doesn't include Windows.h. - const void* sapp_d3d11_get_device(void) const void* sapp_d3d11_get_device_context(void) - const void* sapp_d3d11_get_render_target_view(void) + const void* sapp_d3d11_get_render_view(void) + const void* sapp_d3d11_get_resolve_view(void); const void* sapp_d3d11_get_depth_stencil_view(void) Similar to the sapp_metal_* functions, the sapp_d3d11_* functions return pointers to D3D11 API objects required for rendering, @@ -303,6 +300,11 @@ render-target-view and depth-stencil-view may change from one frame to the next! + const void* sapp_win32_get_hwnd(void) + On Windows, get the window's HWND, otherwise a null pointer. The + HWND has been cast to a void pointer in order to be tunneled + through code which doesn't include Windows.h. + const void* sapp_wgpu_get_device(void) const void* sapp_wgpu_get_render_view(void) const void* sapp_wgpu_get_resolve_view(void) @@ -311,6 +313,10 @@ objects and values required for rendering. If sokol_app.h is not compiled with SOKOL_WGPU, these functions return null. + const uint32_t sapp_gl_get_framebuffer(void) + This returns the 'default framebuffer' of the GL context. + Typically this will be zero. + const void* sapp_android_get_native_activity(void); On Android, get the native activity ANativeActivity pointer, otherwise a null pointer. @@ -1487,7 +1493,6 @@ typedef struct sapp_range { Note that the actual image pixel format depends on the use case: - window icon pixels are RGBA8 - - cursor images are ??? (FIXME) */ typedef struct sapp_image_desc { int width; @@ -1848,10 +1853,12 @@ SOKOL_APP_API_DECL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_req /* Metal: get bridged pointer to Metal device object */ SOKOL_APP_API_DECL const void* sapp_metal_get_device(void); -/* Metal: get bridged pointer to this frame's renderpass descriptor */ -SOKOL_APP_API_DECL const void* sapp_metal_get_renderpass_descriptor(void); -/* Metal: get bridged pointer to current drawable */ -SOKOL_APP_API_DECL const void* sapp_metal_get_drawable(void); +/* Metal: get bridged pointer to MTKView's current drawable of type CAMetalDrawable */ +SOKOL_APP_API_DECL const void* sapp_metal_get_current_drawable(void); +/* Metal: get bridged pointer to MTKView's depth-stencil texture of type MTLTexture */ +SOKOL_APP_API_DECL const void* sapp_metal_get_depth_stencil_texture(void); +/* Metal: get bridged pointer to MTKView's msaa-color-texture of type MTLTexture (may be null) */ +SOKOL_APP_API_DECL const void* sapp_metal_get_msaa_color_texture(void); /* macOS: get bridged pointer to macOS NSWindow */ SOKOL_APP_API_DECL const void* sapp_macos_get_window(void); /* iOS: get bridged pointer to iOS UIWindow */ @@ -1863,9 +1870,11 @@ SOKOL_APP_API_DECL const void* sapp_d3d11_get_device(void); SOKOL_APP_API_DECL const void* sapp_d3d11_get_device_context(void); /* D3D11: get pointer to IDXGISwapChain object */ SOKOL_APP_API_DECL const void* sapp_d3d11_get_swap_chain(void); -/* D3D11: get pointer to ID3D11RenderTargetView object */ -SOKOL_APP_API_DECL const void* sapp_d3d11_get_render_target_view(void); -/* D3D11: get pointer to ID3D11DepthStencilView */ +/* D3D11: get pointer to ID3D11RenderTargetView object for rendering */ +SOKOL_APP_API_DECL const void* sapp_d3d11_get_render_view(void); +/* D3D11: get pointer ID3D11RenderTargetView object for msaa-resolve (may return null) */ +SOKOL_APP_API_DECL const void* sapp_d3d11_get_resolve_view(void); +/* D3D11: get pointer ID3D11DepthStencilView */ SOKOL_APP_API_DECL const void* sapp_d3d11_get_depth_stencil_view(void); /* Win32: get the HWND window handle */ SOKOL_APP_API_DECL const void* sapp_win32_get_hwnd(void); @@ -1879,6 +1888,9 @@ SOKOL_APP_API_DECL const void* sapp_wgpu_get_resolve_view(void); /* WebGPU: get swapchain's WGPUTextureView for the depth-stencil surface */ SOKOL_APP_API_DECL const void* sapp_wgpu_get_depth_stencil_view(void); +/* GL: get framebuffer object */ +SOKOL_APP_API_DECL uint32_t sapp_gl_get_framebuffer(void); + /* Android: get native activity handle */ SOKOL_APP_API_DECL const void* sapp_android_get_native_activity(void); @@ -1983,13 +1995,22 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #if !defined(SOKOL_FORCE_EGL) #define _SAPP_GLX (1) #endif - #elif !defined(SOKOL_GLES3) + #define GL_GLEXT_PROTOTYPES + #include + #elif defined(SOKOL_GLES3) + #include + #include + #else #error("sokol_app.h: unknown 3D API selected for Linux, must be SOKOL_GLCORE33, SOKOL_GLES3") #endif #else #error "sokol_app.h: Unknown platform" #endif +#if defined(SOKOL_GLCORE33) || defined(SOKOL_GLES3) + #define _SAPP_ANY_GL (1) +#endif + #ifndef SOKOL_API_IMPL #define SOKOL_API_IMPL #endif @@ -2023,16 +2044,18 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #import #endif #if defined(_SAPP_MACOS) - #if !defined(SOKOL_METAL) + #if defined(_SAPP_ANY_GL) #ifndef GL_SILENCE_DEPRECATION #define GL_SILENCE_DEPRECATION #endif #include + #include #endif #elif defined(_SAPP_IOS) #import - #if !defined(SOKOL_METAL) + #if defined(_SAPP_ANY_GL) #import + #include #endif #endif #include @@ -2041,6 +2064,9 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #if defined(SOKOL_WGPU) #include #endif + #if defined(SOKOL_GLES3) + #include + #endif #include #include #elif defined(_SAPP_WIN32) @@ -2103,6 +2129,7 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #include #include #include + #include #elif defined(_SAPP_LINUX) #define GL_GLEXT_PROTOTYPES #include @@ -2566,6 +2593,8 @@ typedef struct { PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + // special case glGetIntegerv + void (*GetIntegerv)(uint32_t pname, int32_t* data); bool ext_swap_control; bool arb_multisample; bool arb_pixel_format; @@ -2753,6 +2782,9 @@ typedef struct { PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA; PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + // special case glGetIntegerv + void (*GetIntegerv)(uint32_t pname, int32_t* data); + // extension availability bool EXT_swap_control; bool MESA_swap_control; @@ -2770,9 +2802,14 @@ typedef struct { } _sapp_egl_t; #endif // _SAPP_GLX - #endif // _SAPP_LINUX +#if defined(_SAPP_ANY_GL) +typedef struct { + uint32_t framebuffer; +} _sapp_gl_t; +#endif + typedef struct { bool enabled; int buf_size; @@ -2850,6 +2887,9 @@ typedef struct { _sapp_egl_t egl; #endif #endif + #if defined(_SAPP_ANY_GL) + _sapp_gl_t gl; + #endif char html5_canvas_selector[_SAPP_MAX_TITLE_LENGTH]; char window_title[_SAPP_MAX_TITLE_LENGTH]; // UTF-8 wchar_t window_title_wide[_SAPP_MAX_TITLE_LENGTH]; // UTF-32 or UCS-2 */ @@ -4141,13 +4181,16 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events(void) { - (void)drawRect:(NSRect)rect { _SOKOL_UNUSED(rect); + #if defined(_SAPP_ANY_GL) + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); + #endif _sapp_timing_measure(&_sapp.timing); /* Catch any last-moment input events */ _sapp_macos_poll_input_events(); @autoreleasepool { _sapp_macos_frame(); } - #if !defined(SOKOL_METAL) + #if defined(_SAPP_ANY_GL) [[_sapp.macos.view openGLContext] flushBuffer]; #endif } @@ -4670,6 +4713,9 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { @implementation _sapp_ios_view - (void)drawRect:(CGRect)rect { _SOKOL_UNUSED(rect); + #if defined(_SAPP_ANY_GL) + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); + #endif _sapp_timing_measure(&_sapp.timing); @autoreleasepool { _sapp_ios_frame(); @@ -5552,8 +5598,10 @@ _SOKOL_PRIVATE void _sapp_emsc_webgl_init(void) { EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(_sapp.html5_canvas_selector, &attrs); // FIXME: error message? emscripten_webgl_make_context_current(ctx); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); - /* some WebGL extension are not enabled automatically by emscripten */ + // FIXME: remove PVRTC support here and in sokol-gfx at some point + // some WebGL extension are not enabled automatically by emscripten emscripten_webgl_enable_extension(ctx, "WEBKIT_WEBGL_compressed_texture_pvrtc"); } #endif @@ -6298,14 +6346,6 @@ static inline HRESULT _sapp_d3d11_CreateDepthStencilView(ID3D11Device* self, ID3 #endif } -static inline void _sapp_d3d11_ResolveSubresource(ID3D11DeviceContext* self, ID3D11Resource* pDstResource, UINT DstSubresource, ID3D11Resource* pSrcResource, UINT SrcSubresource, DXGI_FORMAT Format) { - #if defined(__cplusplus) - self->ResolveSubresource(pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); - #else - self->lpVtbl->ResolveSubresource(self, pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); - #endif -} - static inline HRESULT _sapp_dxgi_ResizeBuffers(IDXGISwapChain* self, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) { #if defined(__cplusplus) return self->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags); @@ -6531,12 +6571,6 @@ _SOKOL_PRIVATE void _sapp_d3d11_resize_default_render_target(void) { } _SOKOL_PRIVATE void _sapp_d3d11_present(bool do_not_wait) { - /* do MSAA resolve if needed */ - if (_sapp.sample_count > 1) { - SOKOL_ASSERT(_sapp.d3d11.rt); - SOKOL_ASSERT(_sapp.d3d11.msaa_rt); - _sapp_d3d11_ResolveSubresource(_sapp.d3d11.device_context, (ID3D11Resource*)_sapp.d3d11.rt, 0, (ID3D11Resource*)_sapp.d3d11.msaa_rt, 0, DXGI_FORMAT_B8G8R8A8_UNORM); - } UINT flags = 0; if (_sapp.win32.is_win10_or_greater && do_not_wait) { /* this hack/workaround somewhat improves window-movement and -sizing @@ -6567,6 +6601,8 @@ _SOKOL_PRIVATE void _sapp_wgl_init(void) { SOKOL_ASSERT(_sapp.wgl.GetCurrentDC); _sapp.wgl.MakeCurrent = (PFN_wglMakeCurrent)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglMakeCurrent"); SOKOL_ASSERT(_sapp.wgl.MakeCurrent); + _sapp.wgl.GetIntegerv = (void(*)(uint32_t, int32_t*)) GetProcAddress(_sapp.wgl.opengl32, "glGetIntegerv"); + SOKOL_ASSERT(_sapp.wgl.GetIntegerv); _sapp.wgl.msg_hwnd = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, L"SOKOLAPP", @@ -6831,6 +6867,8 @@ _SOKOL_PRIVATE void _sapp_wgl_create_context(void) { /* FIXME: DwmIsCompositionEnabled() (see GLFW) */ _sapp.wgl.SwapIntervalEXT(_sapp.swap_interval); } + const uint32_t gl_framebuffer_binding = 0x8CA6; + _sapp.wgl.GetIntegerv(gl_framebuffer_binding, (int32_t*)&_sapp.gl.framebuffer); } _SOKOL_PRIVATE void _sapp_wgl_destroy_context(void) { @@ -8107,6 +8145,7 @@ _SOKOL_PRIVATE bool _sapp_android_init_egl_surface(ANativeWindow* window) { return false; } _sapp.android.surface = surface; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); return true; } @@ -9795,6 +9834,11 @@ _SOKOL_PRIVATE void _sapp_glx_choose_visual(Visual** visual, int* depth) { XFree(result); } +_SOKOL_PRIVATE void _sapp_glx_make_current(void) { + _sapp.glx.MakeCurrent(_sapp.x11.display, _sapp.glx.window, _sapp.glx.ctx); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); +} + _SOKOL_PRIVATE void _sapp_glx_create_context(void) { GLXFBConfig native = _sapp_glx_choosefbconfig(); if (0 == native){ @@ -9820,6 +9864,7 @@ _SOKOL_PRIVATE void _sapp_glx_create_context(void) { if (!_sapp.glx.window) { _SAPP_PANIC(LINUX_GLX_CREATE_WINDOW_FAILED); } + _sapp_glx_make_current(); } _SOKOL_PRIVATE void _sapp_glx_destroy_context(void) { @@ -9833,16 +9878,11 @@ _SOKOL_PRIVATE void _sapp_glx_destroy_context(void) { } } -_SOKOL_PRIVATE void _sapp_glx_make_current(void) { - _sapp.glx.MakeCurrent(_sapp.x11.display, _sapp.glx.window, _sapp.glx.ctx); -} - _SOKOL_PRIVATE void _sapp_glx_swap_buffers(void) { _sapp.glx.SwapBuffers(_sapp.x11.display, _sapp.glx.window); } _SOKOL_PRIVATE void _sapp_glx_swapinterval(int interval) { - _sapp_glx_make_current(); if (_sapp.glx.EXT_swap_control) { _sapp.glx.SwapIntervalEXT(_sapp.x11.display, _sapp.glx.window, interval); } @@ -11000,6 +11040,7 @@ _SOKOL_PRIVATE void _sapp_egl_init(void) { if (!eglMakeCurrent(_sapp.egl.display, _sapp.egl.surface, _sapp.egl.surface, _sapp.egl.context)) { _SAPP_PANIC(LINUX_EGL_MAKE_CURRENT_FAILED); } + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer); eglSwapInterval(_sapp.egl.display, _sapp.swap_interval); } @@ -11507,13 +11548,13 @@ SOKOL_API_IMPL const void* sapp_metal_get_device(void) { #endif } -SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { +SOKOL_API_IMPL const void* sapp_metal_get_current_drawable(void) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view currentRenderPassDescriptor]; + const void* obj = (__bridge const void*) [_sapp.macos.view currentDrawable]; #else - const void* obj = (__bridge const void*) [_sapp.ios.view currentRenderPassDescriptor]; + const void* obj = (__bridge const void*) [_sapp.ios.view currentDrawable]; #endif SOKOL_ASSERT(obj); return obj; @@ -11522,15 +11563,28 @@ SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { #endif } -SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { +SOKOL_API_IMPL const void* sapp_metal_get_depth_stencil_texture(void) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view currentDrawable]; + const void* obj = (__bridge const void*) [_sapp.macos.view depthStencilTexture]; #else - const void* obj = (__bridge const void*) [_sapp.ios.view currentDrawable]; + const void* obj = (__bridge const void*) [_sapp.ios.view depthStencilTexture]; + #endif + return obj; + #else + return 0; + #endif +} + +SOKOL_API_IMPL const void* sapp_metal_get_msaa_color_texture(void) { + SOKOL_ASSERT(_sapp.valid); + #if defined(SOKOL_METAL) + #if defined(_SAPP_MACOS) + const void* obj = (__bridge const void*) [_sapp.macos.view multisampleColorTexture]; + #else + const void* obj = (__bridge const void*) [_sapp.ios.view multisampleColorTexture]; #endif - SOKOL_ASSERT(obj); return obj; #else return 0; @@ -11584,14 +11638,29 @@ SOKOL_API_IMPL const void* sapp_d3d11_get_swap_chain(void) { #endif } -SOKOL_API_IMPL const void* sapp_d3d11_get_render_target_view(void) { +SOKOL_API_IMPL const void* sapp_d3d11_get_render_view(void) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_D3D11) - if (_sapp.d3d11.msaa_rtv) { + if (_sapp.sample_count > 1) { + SOKOL_ASSERT(_sapp.d3d11.msaa_rtv); return _sapp.d3d11.msaa_rtv; + } else { + SOKOL_ASSERT(_sapp.d3d11.rtv); + return _sapp.d3d11.rtv; } - else { + #else + return 0; + #endif +} + +SOKOL_API_IMPL const void* sapp_d3d11_get_resolve_view(void) { + SOKOL_ASSERT(_sapp.valid); + #if defined(SOKOL_D3D11) + if (_sapp.sample_count > 1) { + SOKOL_ASSERT(_sapp.d3d11.rtv); return _sapp.d3d11.rtv; + } else { + return 0; } #else return 0; @@ -11629,9 +11698,10 @@ SOKOL_API_IMPL const void* sapp_wgpu_get_render_view(void) { SOKOL_ASSERT(_sapp.valid); #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) if (_sapp.sample_count > 1) { + SOKOL_ASSERT(_sapp.wgpu.msaa_view); return (const void*) _sapp.wgpu.msaa_view; - } - else { + } else { + SOKOL_ASSERT(_sapp.wgpu.swapchain_view); return (const void*) _sapp.wgpu.swapchain_view; } #else @@ -11643,9 +11713,9 @@ SOKOL_API_IMPL const void* sapp_wgpu_get_resolve_view(void) { SOKOL_ASSERT(_sapp.valid); #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) if (_sapp.sample_count > 1) { + SOKOL_ASSERT(_sapp.wgpu.swapchain_view); return (const void*) _sapp.wgpu.swapchain_view; - } - else { + } else { return 0; } #else @@ -11662,6 +11732,15 @@ SOKOL_API_IMPL const void* sapp_wgpu_get_depth_stencil_view(void) { #endif } +SOKOL_API_IMPL uint32_t sapp_gl_get_framebuffer(void) { + SOKOL_ASSERT(_sapp.valid); + #if defined(_SAPP_ANY_GL) + return _sapp.gl.framebuffer; + #else + return 0; + #endif +} + SOKOL_API_IMPL const void* sapp_android_get_native_activity(void) { // NOTE: _sapp.valid is not asserted here because sapp_android_get_native_activity() // needs to be callable from within sokol_main() (see: https://github.com/floooh/sokol/issues/708) diff --git a/src/sokol/c/sokol_gfx.h b/src/sokol/c/sokol_gfx.h index cec6af4..5f74d86 100644 --- a/src/sokol/c/sokol_gfx.h +++ b/src/sokol/c/sokol_gfx.h @@ -89,7 +89,7 @@ sg_setup(const sg_desc*) Depending on the selected 3D backend, sokol-gfx requires some - information, like a device pointer framebuffer pixel formats + information, like a device pointer, default swapchain pixel formats and so on. If you are using sokol_app.h for the window system glue, you can use a helper function provided in the sokol_glue.h header: @@ -99,7 +99,7 @@ #include "sokol_glue.h" //... sg_setup(&(sg_desc){ - .context = sapp_sgcontext(), + .environment = sglue_environment(), }); To get any logging output for errors and from the validation layer, you @@ -113,30 +113,37 @@ }); --- create resource objects (at least buffers, shaders and pipelines, - and optionally images, samplers and passes): + and optionally images, samplers and render-pass-attachments): sg_buffer sg_make_buffer(const sg_buffer_desc*) sg_image sg_make_image(const sg_image_desc*) sg_sampler sg_make_sampler(const sg_sampler_desc*) sg_shader sg_make_shader(const sg_shader_desc*) sg_pipeline sg_make_pipeline(const sg_pipeline_desc*) - sg_pass sg_make_pass(const sg_pass_desc*) + sg_attachments sg_make_attachments(const sg_attachments_desc*) - --- start rendering to the default frame buffer with: + --- start a render pass: - sg_begin_default_pass(const sg_pass_action* action, int width, int height) + sg_begin_pass(const sg_pass* pass); - ...or alternatively with: + Typically, passes render into an externally provided swapchain which + presents the rendering result on the display. Such a 'swapchain pass' + is started like this: - sg_begin_default_passf(const sg_pass_action* action, float width, float height) + sg_begin_pass(&(sg_pass){ .action = { ... }, .swapchain = sglue_swapchain() }) - ...which takes the framebuffer width and height as float values. + ...where .action is an sg_pass_action struct containing actions to be performed + at the start and end of a render pass (such as clearing the render surfaces to + a specific color), and .swapchain is an sg_swapchain + struct all the required information to render into the swapchain's surfaces. - --- or start rendering to an offscreen framebuffer with: + To start an 'offscreen pass' into sokol-gfx image objects, an sg_attachment + object handle is required instead of an sg_swapchain struct. An offscreen + pass is started like this (assuming attachments is an sg_attachments handle): - sg_begin_pass(sg_pass pass, const sg_pass_action* action) + sg_begin_pass(&(sg_pass){ .action = { ... }, .attachments = attachemnts }); - --- set the pipeline state for the next draw call with: + --- set the render pipeline state for the next draw call with: sg_apply_pipeline(sg_pipeline pip) @@ -189,7 +196,7 @@ sg_destroy_sampler(sg_sampler smp) sg_destroy_shader(sg_shader shd) sg_destroy_pipeline(sg_pipeline pip) - sg_destroy_pass(sg_pass pass) + sg_destroy_attachments(sg_attachments atts) --- to set a new viewport rectangle, call @@ -310,7 +317,7 @@ sg_sampler_desc sg_query_sampler_desc(sg_sampler smp) sg_shader_desc sq_query_shader_desc(sg_shader shd) sg_pipeline_desc sg_query_pipeline_desc(sg_pipeline pip) - sg_pass_desc sg_query_pass_desc(sg_pass pass) + sg_attachments_desc sg_query_attachments_desc(sg_attachments atts) ...but NOTE that the returned desc structs may be incomplete, only creation attributes that are kept around internally after resource @@ -330,7 +337,7 @@ sg_sampler_desc sg_query_sampler_defaults(const sg_sampler_desc* desc) sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc) sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc) - sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc) + sg_attachments_desc sg_query_attachments_defaults(const sg_attachments_desc* desc) These functions take a pointer to a desc structure which may contain zero-initialized items for default values. These zero-init values @@ -344,7 +351,7 @@ sg_sampler_info sg_query_sampler_info(sg_sampler smp) sg_shader_info sg_query_shader_info(sg_shader shd) sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip) - sg_pass_info sg_query_pass_info(sg_pass pass) + sg_attachments_info sg_query_attachments_info(sg_attachments atts) ...please note that the returned info-structs are tied quite closely to sokol_gfx.h internals, and may change more often than other @@ -400,17 +407,15 @@ Not all of those limit values are used by all backends, but it is good practice to provide them none-the-less. - (2) 3D-API "context information" (sometimes also called "bindings"): - sokol_gfx.h doesn't create or initialize 3D API objects which are - closely related to the presentation layer (this includes the "rendering - device", the swapchain, and any objects which depend on the - swapchain). These API objects (or callback functions to obtain - them, if those objects might change between frames), must - be provided in a nested sg_context_desc struct inside the - sg_desc struct. If sokol_gfx.h is used together with - sokol_app.h, have a look at the sokol_glue.h header which provides - a convenience function to get a sg_context_desc struct filled out - with context information provided by sokol_app.h + (2) 3D backend "environment information" in a nested sg_environment struct: + - pointers to backend-specific context- or device-objects (for instance + the D3D11, WebGPU or Metal device objects) + - defaults for external swapchain pixel formats and sample counts, + these will be used as default values in image and pipeline objects, + and the sg_swapchain struct passed into sg_begin_pass() + Usually you provide a complete sg_environment struct through + a helper function, as an example look at the sglue_environment() + function in the sokol_glue.h header. See the documentation block of the sg_desc struct below for more information. @@ -428,7 +433,7 @@ passes as textures (it is invalid to use the same image both as render target and as texture in the same pass). - The following sokol-gfx functions must be called inside a render pass: + The following sokol-gfx functions must only be called inside a render pass: sg_apply_viewport(f) sg_apply_scissor_rect(f) @@ -437,21 +442,55 @@ sg_apply_uniforms sg_draw - A frame must have at least one render pass, and this must be the 'default - pass' which renders into the 'default' (swapchain) framebuffer. The default - pass must always be the last pass in the frame before the sg_commit() - call. - - The default and offscreen passes form a dependency tree with the default - pass at the root, offscreen passes as nodes, and render target images as - dependencies between passes. + A frame must have at least one 'swapchain render pass' which renders into an + externally provided swapchain provided as an sg_swapchain struct to the + sg_begin_pass() function. The sg_swapchain struct must contain the + following information: + + - the color pixel-format of the swapchain's render surface + - an optional depth/stencil pixel format if the swapchain + has a depth/stencil buffer + - an optional sample-count for MSAA rendering + - NOTE: the above three values can be zero-initialized, in that + case the defaults from the sg_environment struct will be used that + had been passed to the sg_setup() function. + - a number of backend specific objects: + - GL/GLES3: just a GL framebuffer handle + - D3D11: + - an ID3D11RenderTargetView for the rendering surface + - if MSAA is used, an ID3D11RenderTargetView as + MSAA resolve-target + - an optional ID3D11DepthStencilView for the + depth/stencil buffer + - WebGPU + - a WGPUTextureView object for the rendering surface + - if MSAA is used, a WGPUTextureView object as MSAA resolve target + - an optional WGPUTextureView for the + - Metal (NOTE that the roles of provided surfaces is slightly + different in Metal than in D3D11 or WebGPU, notably, the + CAMetalDrawable is either rendered to directly, or serves + as MSAA resolve target): + - a CAMetalDrawable object which is either rendered + into directly, or in case of MSAA rendering, serves + as MSAA-resolve-target + - if MSAA is used, an multisampled MTLTexture where + rendering goes into + - an optional MTLTexture for the depth/stencil buffer + + It's recommended that you create a helper function which returns an + initialized sg_swapchain struct by value. This can then be directly plugged + into the sg_begin_pass function like this: + + sg_begin_pass(&(sg_pass){ .swapchain = sglue_swapchain() }); + + As an example for such a helper function check out the function sglue_swapchain() + in the sokol_glue.h header. For offscreen render passes, the render target images used in a render pass - are baked into an immutable sg_pass object (for the default pass, the - pass-state is managed internally instead). + are baked into an immutable sg_attachments object. For a simple offscreen scenario with one color-, one depth-stencil-render - target and without multisampling, creating a pass object looks like this: + target and without multisampling, creating an attachment object looks like this: First create two render target images, one with a color pixel format, and one with the depth- or depth-stencil pixel format. Both images @@ -473,24 +512,35 @@ }); NOTE: when creating render target images, have in mind that some default values - are aligned with the default framebuffer attributes, this is sometimes not - what you want: + are aligned with the default environment attributes in the sg_environment struct + that was passed into the sg_setup() call: - - the default values for .pixel_format and .sample_count are the same - as the default framebuffer - - the default value for .num_mipmaps is always 1 + - the default value for sg_image_desc.pixel_format is taken from + sg_environment.defaults.color_format + - the default value for sg_image_desc.sample_count is taken from + sg_environment.defaults.sample_count + - the default value for sg_image_desc.num_mipmaps is always 1 - Next create a pass object: + Next create an attachments object: - const sg_pass pass = sg_make_pass(&(sg_pass_desc){ - .color_attachments[0].image = color_img, - .depth_stencil_attachment.image = depth_img, + const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ + .colors[0].image = color_img, + .depth_stencil.image = depth_img, }); - When using the sg_pass object in a render pass you also need to define - what actions should happen at the start and end of the render pass - in an sg_pass_action struct (for instance whether the render target should - be cleared). + This attachments object is then passed into the sg_begin_pass() function + in place of the swapchain struct: + + sg_begin_pass(&(sg_pass){ .attachments = atts }); + + Swapchain and offscreen passes form dependency trees each with a swapchain + pass at the root, offscreen passes as nodes, and render target images as + dependencies between passes. + + sg_pass_action structs are used to define actions that should happen at the + start and end of rendering passes (such as clearing pass attachments to a + specific color or depth-value, or performing an MSAA resolve operation at + the end of a pass). A typical sg_pass_action object which clears the color attachment to black might look like this: @@ -506,7 +556,7 @@ the depth-stencil-attachments actions. The same pass action with the defaults explicitly filled in would look like this: - const sg_pass_action = { + const sg_pass_action pass_action = { .colors[0] = { .load_action = SG_LOADACTION_CLEAR, .store_action = SG_STOREACTION_STORE, @@ -527,7 +577,22 @@ With the sg_pass object and sg_pass_action struct in place everything is ready now for the actual render pass: - sg_begin_pass(pass, &pass_action); + Using such this prepared sg_pass_action in a swapchain pass looks like + this: + + sg_begin_pass(&(sg_pass){ + .action = pass_action, + .swapchain = sglue_swapchain() + }); + ... + sg_end_pass(); + + ...of alternatively in one offscreen pass: + + sg_begin_pass(&(sg_pass){ + .action = pass_action, + .attachments = attachments, + }); ... sg_end_pass(); @@ -536,16 +601,16 @@ it's not possible to create a 3D image with a depth/stencil pixel format, these exceptions are generally caught by the sokol-gfx validation layer). - The mipmap/slice selection happens at pass creation time, for instance + The mipmap/slice selection happens at attachments creation time, for instance to render into mipmap 2 of slice 3 of an array texture: - const sg_pass pass = sg_make_pass(&(sg_pass_desc){ - .color_attachments[0] = { + const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ + .colors[0] = { .image = color_img, .mip_level = 2, .slice = 3, }, - .depth_stencil_attachment.image = depth_img, + .depth_stencil.image = depth_img, }); If MSAA offscreen rendering is desired, the multi-sample rendering result @@ -554,7 +619,7 @@ NOTE: currently multisample-images cannot be bound as textures. - Creating a simple pass object for multisampled rendering requires + Creating a simple attachments object for multisampled rendering requires 3 attachment images: the color attachment image which has a sample count > 1, a resolve attachment image of the same size and pixel format but a sample count == 1, and a depth/stencil attachment image with @@ -582,15 +647,15 @@ .sample_count = 4, }); - ...create the pass object: + ...create the attachments object: - const sg_pass pass = sg_make_pass(&(sg_pass_desc){ - .color_attachments[0].image = color_img, - .resolve_attachments[0].image = resolve_img, - .depth_stencil_attachment.image = depth_img, + const sg_attachments atts = sg_make_attachments(&(sg_attachments_desc){ + .colors[0].image = color_img, + .resolves[0].image = resolve_img, + .depth_stencil.image = depth_img, }); - If a pass object defines a resolve image in a specific resolve attachment slot, + If an attachments object defines a resolve image in a specific resolve attachment slot, an 'msaa resolve operation' will happen in sg_end_pass(). In this scenario, the content of the MSAA color attachment doesn't need to be @@ -607,7 +672,7 @@ The actual render pass looks as usual: - sg_begin_pass(pass, &pass_action); + sg_begin_pass(&(sg_pass){ .action = pass_action, .attachments = atts }); ... sg_end_pass(); @@ -889,50 +954,6 @@ to use the sokol-shdc shader cross-compiler tool! - WORKING WITH CONTEXTS - ===================== - sokol-gfx allows to switch between different rendering contexts and - associate resource objects with contexts. This is useful to - create GL applications that render into multiple windows. - - A rendering context keeps track of all resources created while - the context is active. When the context is destroyed, all resources - "belonging to the context" are destroyed as well. - - A default context will be created and activated implicitly in - sg_setup(), and destroyed in sg_shutdown(). So for a typical application - which *doesn't* use multiple contexts, nothing changes, and calling - the context functions isn't necessary. - - Three functions have been added to work with contexts: - - --- sg_context sg_setup_context(): - This must be called once after a GL context has been created and - made active. - - --- void sg_activate_context(sg_context ctx) - This must be called after making a different GL context active. - Apart from 3D-API-specific actions, the call to sg_activate_context() - will internally call sg_reset_state_cache(). - - --- void sg_discard_context(sg_context ctx) - This must be called right before a GL context is destroyed and - will destroy all resources associated with the context (that - have been created while the context was active) The GL context must be - active at the time sg_discard_context(sg_context ctx) is called. - - Also note that resources (buffers, images, shaders and pipelines) must - only be used or destroyed while the same GL context is active that - was also active while the resource was created (an exception is - resource sharing on GL, such resources can be used while - another context is active, but must still be destroyed under - the same context that was active during creation). - - For more information, check out the multiwindow-glfw sample: - - https://github.com/floooh/sokol-samples/blob/master/glfw/multiwindow-glfw.c - - TRACE HOOKS: ============ sokol_gfx.h optionally allows to install "trace hook" callbacks for @@ -1134,7 +1155,7 @@ sg_sampler sg_make_sampler(const sg_sampler_desc* desc) sg_shader sg_make_shader(const sg_shader_desc* desc) sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc) - sg_pass sg_make_pass(const sg_pass_desc* desc) + sg_attachments sg_make_attachments(const sg_attachments_desc* desc) This will result in one of three cases: @@ -1192,7 +1213,7 @@ sg_sampler sg_alloc_sampler(void) sg_shader sg_alloc_shader(void) sg_pipeline sg_alloc_pipeline(void) - sg_pass sg_alloc_pass(void) + sg_attachments sg_alloc_attachments(void) This will return a handle with the underlying resource object in the ALLOC state: @@ -1217,7 +1238,7 @@ void sg_init_sampler(sg_sampler smp, const sg_sampler_desc* desc) void sg_init_shader(sg_shader shd, const sg_shader_desc* desc) void sg_init_pipeline(sg_pipeline pip, const sg_pipeline_desc* desc) - void sg_init_pass(sg_pass pass, const sg_pass_desc* desc) + void sg_init_attachments(sg_attachments atts, const sg_attachments_desc* desc) The init functions expect a resource in ALLOC state, and after the function returns, the resource will be either in VALID or FAILED state. Calling @@ -1233,7 +1254,7 @@ void sg_uninit_sampler(sg_sampler smp) void sg_uninit_shader(sg_shader shd) void sg_uninit_pipeline(sg_pipeline pip) - void sg_uninit_pass(sg_pass pass) + void sg_uninit_attachments(sg_attachments pass) Calling the 'uninit functions' with a resource that is not in the VALID or FAILED state is a no-op. @@ -1245,7 +1266,7 @@ void sg_dealloc_sampler(sg_sampler smp) void sg_dealloc_shader(sg_shader shd) void sg_dealloc_pipeline(sg_pipeline pip) - void sg_dealloc_pass(sg_pass pass) + void sg_dealloc_attachments(sg_attachments atts) Calling the 'dealloc functions' on a resource that's not in ALLOC state is a no-op, but will generate a warning log message. @@ -1258,7 +1279,7 @@ void sg_destroy_sampler(sg_sampler smp) void sg_destroy_shader(sg_shader shd) void sg_destroy_pipeline(sg_pipeline pip) - void sg_destroy_pass(sg_pass pass) + void sg_destroy_attachments(sg_attachments atts) The 'destroy functions' can be called on resources in any state and generally do the right thing (for instance if the resource is in ALLOC state, the destroy @@ -1272,21 +1293,21 @@ sg_fail_sampler(sg_sampler smp) sg_fail_shader(sg_shader shd) sg_fail_pipeline(sg_pipeline pip) - sg_fail_pass(sg_pass pass) + sg_fail_attachments(sg_attachments atts) This is recommended if anything went wrong outside of sokol-gfx during asynchronous - resource creation (for instance a file loading operation failed). In this case, + resource setup (for instance a file loading operation failed). In this case, the 'fail function' should be called instead of the 'init function'. Calling a 'fail function' on a resource that's not in ALLOC state is a no-op, but will generate a warning log message. NOTE: that two-step resource creation usually only makes sense for buffers - and images, but not for samplers, shaders, pipelines or passes. Most notably, trying + and images, but not for samplers, shaders, pipelines or attachments. Most notably, trying to create a pipeline object with a shader that's not in VALID state will trigger a validation layer error, or if the validation layer is disabled, result in a pipeline object in FAILED state. Same when trying to create - a pass object with invalid image objects. + an attachments object with invalid image objects. WEBGPU CAVEATS @@ -1298,7 +1319,7 @@ In general, don't expect an automatic speedup when switching from the WebGL2 backend to the WebGPU backend. Some WebGPU functions currently actually have a higher CPU overhead than similar WebGL2 functions, leading to the - paradoxical situation that WebGPU code is slower than similar WebGL2 + paradoxical situation that some WebGPU code may be slower than similar WebGL2 code. - when writing WGSL shader code by hand, a specific bind-slot convention @@ -1338,7 +1359,7 @@ cache to prevent excessive creation and destruction of BindGroup objects when calling sg_apply_bindings(). The number of slots in the bindgroups cache is defined in sg_desc.wgpu_bindgroups_cache_size when calling - sg_setup. The cache size must be a power-of-2 numbers, with the default being + sg_setup. The cache size must be a power-of-2 number, with the default being 1024. The bindgroups cache behaviour can be observed by calling the new function sg_query_frame_stats(), where the following struct items are of interest: @@ -1362,7 +1383,7 @@ - The sokol shader compiler generally adds `diagnostic(off, derivative_uniformity);` into the WGSL output. Currently only the Chrome WebGPU implementation seems - to accept this. + to recognize this. - The vertex format SG_VERTEXFORMAT_UINT10_N2 is currently not supported because WebGPU lacks a matching vertex format (this is currently being worked on though, @@ -1378,10 +1399,10 @@ will generate broken Javascript code. - sokol-gfx requires the WebGPU device feature `depth32float-stencil8` to be enabled - (this should be supported widely supported) + (this should be widely supported) - sokol-gfx expects that the WebGPU device feature `float32-filterable` to *not* be - enabled (this would exclude all iOS devices) + enabled (since this would exclude all iOS devices) LICENSE @@ -1439,28 +1460,26 @@ extern "C" { sg_sampler sampler object describing how a texture is sampled in a shader sg_shader: vertex- and fragment-shaders and shader interface information sg_pipeline: associated shader and vertex-layouts, and render states - sg_pass: a bundle of render targets and actions on them - sg_context: a 'context handle' for switching between 3D-API contexts + sg_attachments: a baked collection of render pass attachment images Instead of pointers, resource creation functions return a 32-bit number which uniquely identifies the resource object. The 32-bit resource id is split into a 16-bit pool index in the lower bits, - and a 16-bit 'unique counter' in the upper bits. The index allows fast - pool lookups, and combined with the unique-mask it allows to detect + and a 16-bit 'generation counter' in the upper bits. The index allows fast + pool lookups, and combined with the generation-counter it allows to detect 'dangling accesses' (trying to use an object which no longer exists, and its pool slot has been reused for a new object) - The resource ids are wrapped into a struct so that the compiler - can complain when the wrong resource type is used. + The resource ids are wrapped into a strongly-typed struct so that + trying to pass an incompatible resource id is a compile error. */ -typedef struct sg_buffer { uint32_t id; } sg_buffer; -typedef struct sg_image { uint32_t id; } sg_image; -typedef struct sg_sampler { uint32_t id; } sg_sampler; -typedef struct sg_shader { uint32_t id; } sg_shader; -typedef struct sg_pipeline { uint32_t id; } sg_pipeline; -typedef struct sg_pass { uint32_t id; } sg_pass; -typedef struct sg_context { uint32_t id; } sg_context; +typedef struct sg_buffer { uint32_t id; } sg_buffer; +typedef struct sg_image { uint32_t id; } sg_image; +typedef struct sg_sampler { uint32_t id; } sg_sampler; +typedef struct sg_shader { uint32_t id; } sg_shader; +typedef struct sg_pipeline { uint32_t id; } sg_pipeline; +typedef struct sg_attachments { uint32_t id; } sg_attachments; /* sg_range is a pointer-size-pair struct used to pass memory blobs into @@ -1564,14 +1583,12 @@ typedef enum sg_backend { The default pixel format for texture images is SG_PIXELFORMAT_RGBA8. - The default pixel format for render target images is platform-dependent: - - for Metal and D3D11 it is SG_PIXELFORMAT_BGRA8 - - for GL backends it is SG_PIXELFORMAT_RGBA8 + The default pixel format for render target images is platform-dependent + and taken from the sg_environment struct passed into sg_setup(). Typically + the default formats are: - This is mainly because of the default framebuffer which is setup outside - of sokol_gfx.h. On some backends, using BGRA for the default frame buffer - allows more efficient frame flips. For your own offscreen-render-targets, - use whatever renderable pixel format is convenient for you. + - for the Metal, D3D11 and WebGPU backends: SG_PIXELFORMAT_BGRA8 + - for GL backends: SG_PIXELFORMAT_RGBA8 */ typedef enum sg_pixel_format { _SG_PIXELFORMAT_DEFAULT, // value 0 reserved for default-init @@ -1623,7 +1640,7 @@ typedef enum sg_pixel_format { SG_PIXELFORMAT_RGBA32SI, SG_PIXELFORMAT_RGBA32F, - // NOTE: when adding/removing pixel formats before DEPTH, also update sokol_app.h/SAPP_PIXELFORMAT_* + // NOTE: when adding/removing pixel formats before DEPTH, also update sokol_app.h/_SAPP_PIXELFORMAT_* SG_PIXELFORMAT_DEPTH, SG_PIXELFORMAT_DEPTH_STENCIL, @@ -1640,10 +1657,10 @@ typedef enum sg_pixel_format { SG_PIXELFORMAT_BC6H_RGBUF, SG_PIXELFORMAT_BC7_RGBA, SG_PIXELFORMAT_BC7_SRGBA, - SG_PIXELFORMAT_PVRTC_RGB_2BPP, - SG_PIXELFORMAT_PVRTC_RGB_4BPP, - SG_PIXELFORMAT_PVRTC_RGBA_2BPP, - SG_PIXELFORMAT_PVRTC_RGBA_4BPP, + SG_PIXELFORMAT_PVRTC_RGB_2BPP, // FIXME: deprecated + SG_PIXELFORMAT_PVRTC_RGB_4BPP, // FIXME: deprecated + SG_PIXELFORMAT_PVRTC_RGBA_2BPP, // FIXME: deprecated + SG_PIXELFORMAT_PVRTC_RGBA_4BPP, // FIXME: deprecated SG_PIXELFORMAT_ETC2_RGB8, SG_PIXELFORMAT_ETC2_SRGB8, SG_PIXELFORMAT_ETC2_RGB8A1, @@ -1695,7 +1712,7 @@ typedef struct sg_limits { int max_image_size_array; // max width/height of SG_IMAGETYPE_ARRAY images int max_image_array_layers; // max number of layers in SG_IMAGETYPE_ARRAY images int max_vertex_attrs; // max number of vertex attributes, clamped to SG_MAX_VERTEX_ATTRIBUTES - int gl_max_vertex_uniform_vectors; // <= GL_MAX_VERTEX_UNIFORM_VECTORS (only on GL backends) + int gl_max_vertex_uniform_components; // <= GL_MAX_VERTEX_UNIFORM_COMPONENTS (only on GL backends) int gl_max_combined_texture_image_units; // <= GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (only on GL backends) } sg_limits; @@ -1831,8 +1848,10 @@ typedef enum sg_image_type { The basic data type of a texture sample as expected by a shader. Must be provided in sg_shader_image_desc and used by the validation layer in sg_apply_bindings() to check if the provided image object - is compatible with what the shader expects, and also required by the - WebGPU backend. + is compatible with what the shader expects. Apart from the sokol-gfx + validation layer, WebGPU is the only backend API which actually requires + matching texture and sampler type to be provided upfront for validation + (after 3D APIs treat texture/sampler type mismatches as undefined behaviour). NOTE that the following texture pixel formats require the use of SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT, combined with a sampler @@ -1842,7 +1861,7 @@ typedef enum sg_image_type { - SG_PIXELFORMAT_RG32F - SG_PIXELFORMAT_RGBA32F - (when using sokol-shdc, also check out the tags `@image_sample_type` + (when using sokol-shdc, also check out the meta tags `@image_sample_type` and `@sampler_type`) */ typedef enum sg_image_sample_type { @@ -1948,7 +1967,7 @@ typedef enum sg_primitive_type { */ typedef enum sg_filter { _SG_FILTER_DEFAULT, // value 0 reserved for default-init - SG_FILTER_NONE, + SG_FILTER_NONE, // FIXME: deprecated SG_FILTER_NEAREST, SG_FILTER_LINEAR, _SG_FILTER_NUM, @@ -2358,13 +2377,13 @@ typedef enum sg_store_action { sg_pass_action The sg_pass_action struct defines the actions to be performed - at the start of and end of a render pass. + at the start and end of a render pass. - - at the start of the pass whether the render targets should be cleared + - at the start of the pass: whether the render targets should be cleared, loaded with their previous content, or start in an undefined state - for clear operations: the clear value (color, depth, or stencil values) - - at the end of the pass, whether the rendering result should be - stored back into the render target, or discarded + - at the end of the pass: whether the rendering result should be + stored back into the render target or discarded */ typedef struct sg_color_attachment_action { sg_load_action load_action; // default: SG_LOADACTION_CLEAR @@ -2385,13 +2404,149 @@ typedef struct sg_stencil_attachment_action { } sg_stencil_attachment_action; typedef struct sg_pass_action { - uint32_t _start_canary; sg_color_attachment_action colors[SG_MAX_COLOR_ATTACHMENTS]; sg_depth_attachment_action depth; sg_stencil_attachment_action stencil; - uint32_t _end_canary; } sg_pass_action; +/* + sg_swapchain + + Used in sg_begin_pass() to provide details about an external swapchain + (pixel formats, sample count and backend-API specific render surface objects). + + The following information must be provided: + + - the width and height of the swapchain surfaces in number of pixels, + - the pixel format of the render- and optional msaa-resolve-surface + - the pixel format of the optional depth- or depth-stencil-surface + - the MSAA sample count for the render and depth-stencil surface + + If the pixel formats and MSAA sample counts are left zero-initialized, + their defaults are taken from the sg_environment struct provided in the + sg_setup() call. + + The width and height *must* be > 0. + + Additionally the following backend API specific objects must be passed in + as 'type erased' void pointers: + + GL: on all GL backends, a GL framebuffer object must be provided. This + can be zero for the defaul framebuffer. + + D3D11: + - an ID3D11RenderTargetView for the rendering surface, without + MSAA rendering this surface will also be displayed + - an optional ID3D11DepthStencilView for the depth- or depth/stencil + buffer surface + - when MSAA rendering is used, another ID3D11RenderTargetView + which serves as MSAA resolve target and will be displayed + + WebGPU (same as D3D11, except different types) + - a WGPUTextureView for the rendering surface, without + MSAA rendering this surface will also be displayed + - an optional WGPUTextureView for the depth- or depth/stencil + buffer surface + - when MSAA rendering is used, another WGPUTextureView + which serves as MSAA resolve target and will be displayed + + Metal (NOTE that the rolves of provided surfaces is slightly different + than on D3D11 or WebGPU in case of MSAA vs non-MSAA rendering): + + - A current CAMetalDrawable (NOT an MTLDrawable!) which will be presented. + This will either be rendered to directly (if no MSAA is used), or serve + as MSAA-resolve target. + - an optional MTLTexture for the depth- or depth-stencil buffer + - an optional multisampled MTLTexture which serves as intermediate + rendering surface which will then be resolved into the + CAMetalDrawable. + + NOTE that for Metal you must use an ObjC __bridge cast to + properly tunnel the ObjC object handle through a C void*, e.g.: + + swapchain.metal.current_drawable = (__bridge const void*) [mtkView currentDrawable]; + + On all other backends you shouldn't need to mess with the reference count. + + It's a good practice to write a helper function which returns an initialized + sg_swapchain structs, which can then be plugged directly into + sg_pass.swapchain. Look at the function sglue_swapchain() in the sokol_glue.h + as an example. +*/ +typedef struct sg_metal_swapchain { + const void* current_drawable; // CAMetalDrawable (NOT MTLDrawable!!!) + const void* depth_stencil_texture; // MTLTexture + const void* msaa_color_texture; // MTLTexture +} sg_metal_swapchain; + +typedef struct sg_d3d11_swapchain { + const void* render_view; // ID3D11RenderTargetView + const void* resolve_view; // ID3D11RenderTargetView + const void* depth_stencil_view; // ID3D11DepthStencilView +} sg_d3d11_swapchain; + +typedef struct sg_wgpu_swapchain { + const void* render_view; // WGPUTextureView + const void* resolve_view; // WGPUTextureView + const void* depth_stencil_view; // WGPUTextureView +} sg_wgpu_swapchain; + +typedef struct sg_gl_swapchain { + uint32_t framebuffer; // GL framebuffer object +} sg_gl_swapchain; + +typedef struct sg_swapchain { + int width; + int height; + int sample_count; + sg_pixel_format color_format; + sg_pixel_format depth_format; + sg_metal_swapchain metal; + sg_d3d11_swapchain d3d11; + sg_wgpu_swapchain wgpu; + sg_gl_swapchain gl; +} sg_swapchain; + +/* + sg_pass + + The sg_pass structure is passed as argument into the sg_begin_pass() + function. + + For an offscreen rendering pass, an sg_pass_action struct and sg_attachments + object must be provided, and for swapchain passes, and sg_pass_action and + an sg_swapchain struct. It is an error to provide both an sg_attachments + handle and an initialized sg_swapchain struct in the same sg_begin_pass(). + + An sg_begin_pass() call for an offscreen pass would look like this (where + `attachments` is an sg_attachments handle): + + sg_begin_pass(&(sg_pass){ + .action = { ... }, + .attachments = attachments, + }); + + ...and a swapchain render pass would look like this (using the sokol_glue.h + helper function sglue_swapchain() which gets the swapchain properties from + sokol_app.h): + + sg_begin_pass(&(sg_pass){ + .action = { ... }, + .swapchain = sglue_swapchain(), + }); + + You can also omit the .action object to get default pass action behaviour + (clear to color=grey, depth=1 and stencil=0). +*/ +typedef struct sg_pass { + uint32_t _start_canary; + sg_pass_action action; + sg_attachments attachments; + sg_swapchain swapchain; + const char* label; + uint32_t _end_canary; +} sg_pass; + /* sg_bindings @@ -2526,17 +2681,17 @@ typedef struct sg_image_data { .num_slices 1 (3D textures: depth; array textures: number of layers) .num_mipmaps: 1 .usage: SG_USAGE_IMMUTABLE - .pixel_format: SG_PIXELFORMAT_RGBA8 for textures, or sg_desc.context.color_format for render targets - .sample_count: 1 for textures, or sg_desc.context.sample_count for render targets + .pixel_format: SG_PIXELFORMAT_RGBA8 for textures, or sg_desc.environment.defaults.color_format for render targets + .sample_count: 1 for textures, or sg_desc.environment.defaults.sample_count for render targets .data an sg_image_data struct to define the initial content .label 0 (optional string label for trace hooks) Q: Why is the default sample_count for render targets identical with the - "default sample count" from sg_desc.context.sample_count? + "default sample count" from sg_desc.environment.defaults.sample_count? A: So that it matches the default sample count in pipeline objects. Even though it is a bit strange/confusing that offscreen render targets by default - get the same sample count as the default framebuffer, but it's better that + get the same sample count as 'default swapchains', but it's better that an offscreen render target created with default parameters matches a pipeline object created with default parameters. @@ -2877,16 +3032,19 @@ typedef struct sg_pipeline_desc { } sg_pipeline_desc; /* - sg_pass_desc + sg_attachments_desc - Creation parameters for an sg_pass object, used as argument to the - sg_make_pass() function. + Creation parameters for an sg_attachments object, used as argument to the + sg_make_attachments() function. - A pass object contains 1..4 color attachments, 0..4 msaa-resolve - attachments, and none or one depth-stencil attachment. + An attachments object bundles 0..4 color attachments, 0..4 msaa-resolve + attachments, and none or one depth-stencil attachmente for use + in a render pass. At least one color attachment or one depth-stencil + attachment must be provided (no color attachment and a depth-stencil + attachment is useful for a depth-only render pass). - Each attachment consists of an image, and two additional indices describing - which subimage the pass will render into: one mipmap index, and if the image + Each attachment definition consists of an image object, and two additional indices + describing which subimage the pass will render into: one mipmap index, and if the image is a cubemap, array-texture or 3D-texture, the face-index, array-layer or depth-slice. @@ -2896,7 +3054,7 @@ typedef struct sg_pipeline_desc { same sample count. If a resolve attachment is set, an MSAA-resolve operation from the - associated color attachment into the resolve attachment image will take + associated color attachment image into the resolve attachment image will take place in the sg_end_pass() function. In this case, the color attachment must have a (sample_count>1), and the resolve attachment a (sample_count==1). The resolve attachment also must have the same pixel @@ -2904,20 +3062,20 @@ typedef struct sg_pipeline_desc { NOTE that MSAA depth-stencil attachments cannot be msaa-resolved! */ -typedef struct sg_pass_attachment_desc { +typedef struct sg_attachment_desc { sg_image image; int mip_level; int slice; // cube texture: face; array texture: layer; 3D texture: slice -} sg_pass_attachment_desc; +} sg_attachment_desc; -typedef struct sg_pass_desc { +typedef struct sg_attachments_desc { uint32_t _start_canary; - sg_pass_attachment_desc color_attachments[SG_MAX_COLOR_ATTACHMENTS]; - sg_pass_attachment_desc resolve_attachments[SG_MAX_COLOR_ATTACHMENTS]; - sg_pass_attachment_desc depth_stencil_attachment; + sg_attachment_desc colors[SG_MAX_COLOR_ATTACHMENTS]; + sg_attachment_desc resolves[SG_MAX_COLOR_ATTACHMENTS]; + sg_attachment_desc depth_stencil; const char* label; uint32_t _end_canary; -} sg_pass_desc; +} sg_attachments_desc; /* sg_trace_hooks @@ -2939,18 +3097,17 @@ typedef struct sg_trace_hooks { void (*make_sampler)(const sg_sampler_desc* desc, sg_sampler result, void* user_data); void (*make_shader)(const sg_shader_desc* desc, sg_shader result, void* user_data); void (*make_pipeline)(const sg_pipeline_desc* desc, sg_pipeline result, void* user_data); - void (*make_pass)(const sg_pass_desc* desc, sg_pass result, void* user_data); + void (*make_attachments)(const sg_attachments_desc* desc, sg_attachments result, void* user_data); void (*destroy_buffer)(sg_buffer buf, void* user_data); void (*destroy_image)(sg_image img, void* user_data); void (*destroy_sampler)(sg_sampler smp, void* user_data); void (*destroy_shader)(sg_shader shd, void* user_data); void (*destroy_pipeline)(sg_pipeline pip, void* user_data); - void (*destroy_pass)(sg_pass pass, void* user_data); + void (*destroy_attachments)(sg_attachments atts, void* user_data); void (*update_buffer)(sg_buffer buf, const sg_range* data, void* user_data); void (*update_image)(sg_image img, const sg_image_data* data, void* user_data); void (*append_buffer)(sg_buffer buf, const sg_range* data, int result, void* user_data); - void (*begin_default_pass)(const sg_pass_action* pass_action, int width, int height, void* user_data); - void (*begin_pass)(sg_pass pass, const sg_pass_action* pass_action, void* user_data); + void (*begin_pass)(const sg_pass* pass, void* user_data); void (*apply_viewport)(int x, int y, int width, int height, bool origin_top_left, void* user_data); void (*apply_scissor_rect)(int x, int y, int width, int height, bool origin_top_left, void* user_data); void (*apply_pipeline)(sg_pipeline pip, void* user_data); @@ -2964,31 +3121,31 @@ typedef struct sg_trace_hooks { void (*alloc_sampler)(sg_sampler result, void* user_data); void (*alloc_shader)(sg_shader result, void* user_data); void (*alloc_pipeline)(sg_pipeline result, void* user_data); - void (*alloc_pass)(sg_pass result, void* user_data); + void (*alloc_attachments)(sg_attachments result, void* user_data); void (*dealloc_buffer)(sg_buffer buf_id, void* user_data); void (*dealloc_image)(sg_image img_id, void* user_data); void (*dealloc_sampler)(sg_sampler smp_id, void* user_data); void (*dealloc_shader)(sg_shader shd_id, void* user_data); void (*dealloc_pipeline)(sg_pipeline pip_id, void* user_data); - void (*dealloc_pass)(sg_pass pass_id, void* user_data); + void (*dealloc_attachments)(sg_attachments atts_id, void* user_data); void (*init_buffer)(sg_buffer buf_id, const sg_buffer_desc* desc, void* user_data); void (*init_image)(sg_image img_id, const sg_image_desc* desc, void* user_data); void (*init_sampler)(sg_sampler smp_id, const sg_sampler_desc* desc, void* user_data); void (*init_shader)(sg_shader shd_id, const sg_shader_desc* desc, void* user_data); void (*init_pipeline)(sg_pipeline pip_id, const sg_pipeline_desc* desc, void* user_data); - void (*init_pass)(sg_pass pass_id, const sg_pass_desc* desc, void* user_data); + void (*init_attachments)(sg_attachments atts_id, const sg_attachments_desc* desc, void* user_data); void (*uninit_buffer)(sg_buffer buf_id, void* user_data); void (*uninit_image)(sg_image img_id, void* user_data); void (*uninit_sampler)(sg_sampler smp_id, void* user_data); void (*uninit_shader)(sg_shader shd_id, void* user_data); void (*uninit_pipeline)(sg_pipeline pip_id, void* user_data); - void (*uninit_pass)(sg_pass pass_id, void* user_data); + void (*uninit_attachments)(sg_attachments atts_id, void* user_data); void (*fail_buffer)(sg_buffer buf_id, void* user_data); void (*fail_image)(sg_image img_id, void* user_data); void (*fail_sampler)(sg_sampler smp_id, void* user_data); void (*fail_shader)(sg_shader shd_id, void* user_data); void (*fail_pipeline)(sg_pipeline pip_id, void* user_data); - void (*fail_pass)(sg_pass pass_id, void* user_data); + void (*fail_attachments)(sg_attachments atts_id, void* user_data); void (*push_debug_group)(const char* name, void* user_data); void (*pop_debug_group)(void* user_data); } sg_trace_hooks; @@ -2999,7 +3156,7 @@ typedef struct sg_trace_hooks { sg_sampler_info sg_shader_info sg_pipeline_info - sg_pass_info + sg_attachments_info These structs contain various internal resource attributes which might be useful for debug-inspection. Please don't rely on the @@ -3019,7 +3176,6 @@ typedef struct sg_trace_hooks { typedef struct sg_slot_info { sg_resource_state state; // the current state of this resource slot uint32_t res_id; // type-neutral resource if (e.g. sg_buffer.id) - uint32_t ctx_id; // the context this resource belongs to } sg_slot_info; typedef struct sg_buffer_info { @@ -3051,9 +3207,9 @@ typedef struct sg_pipeline_info { sg_slot_info slot; // resource pool slot info } sg_pipeline_info; -typedef struct sg_pass_info { +typedef struct sg_attachments_info { sg_slot_info slot; // resource pool slot info -} sg_pass_info; +} sg_attachments_info; /* sg_frame_stats @@ -3283,13 +3439,7 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(WGPU_SHADER_CREATE_BINDGROUP_LAYOUT_FAILED, "wgpuDeviceCreateBindGroupLayout() for shader stage failed") \ _SG_LOGITEM_XMACRO(WGPU_CREATE_PIPELINE_LAYOUT_FAILED, "wgpuDeviceCreatePipelineLayout() failed") \ _SG_LOGITEM_XMACRO(WGPU_CREATE_RENDER_PIPELINE_FAILED, "wgpuDeviceCreateRenderPipeline() failed") \ - _SG_LOGITEM_XMACRO(WGPU_PASS_CREATE_TEXTURE_VIEW_FAILED, "wgpuTextureCreateView() failed in create pass") \ - _SG_LOGITEM_XMACRO(UNINIT_BUFFER_ACTIVE_CONTEXT_MISMATCH, "active context mismatch in buffer uninit (must be same as for creation)") \ - _SG_LOGITEM_XMACRO(UNINIT_IMAGE_ACTIVE_CONTEXT_MISMATCH, "active context mismatch in image uninit (must be same as for creation)") \ - _SG_LOGITEM_XMACRO(UNINIT_SAMPLER_ACTIVE_CONTEXT_MISMATCH, "active context mismatch in sampler uninit (must be same as for creation)") \ - _SG_LOGITEM_XMACRO(UNINIT_SHADER_ACTIVE_CONTEXT_MISMATCH, "active context mismatch in shader uninit (must be same as for creation)") \ - _SG_LOGITEM_XMACRO(UNINIT_PIPELINE_ACTIVE_CONTEXT_MISMATCH, "active context mismatch in pipeline uninit (must be same as for creation)") \ - _SG_LOGITEM_XMACRO(UNINIT_PASS_ACTIVE_CONTEXT_MISMATCH, "active context mismatch in pass uninit (must be same as for creation)") \ + _SG_LOGITEM_XMACRO(WGPU_ATTACHMENTS_CREATE_TEXTURE_VIEW_FAILED, "wgpuTextureCreateView() failed in create attachments") \ _SG_LOGITEM_XMACRO(IDENTICAL_COMMIT_LISTENER, "attempting to add identical commit listener") \ _SG_LOGITEM_XMACRO(COMMIT_LISTENER_ARRAY_FULL, "commit listener array full") \ _SG_LOGITEM_XMACRO(TRACE_HOOKS_NOT_ENABLED, "sg_install_trace_hooks() called, but SG_TRACE_HOOKS is not defined") \ @@ -3298,31 +3448,32 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(DEALLOC_SAMPLER_INVALID_STATE, "sg_dealloc_sampler(): sampler must be in alloc state") \ _SG_LOGITEM_XMACRO(DEALLOC_SHADER_INVALID_STATE, "sg_dealloc_shader(): shader must be in ALLOC state") \ _SG_LOGITEM_XMACRO(DEALLOC_PIPELINE_INVALID_STATE, "sg_dealloc_pipeline(): pipeline must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(DEALLOC_PASS_INVALID_STATE, "sg_dealloc_pass(): pass must be in ALLOC state") \ + _SG_LOGITEM_XMACRO(DEALLOC_ATTACHMENTS_INVALID_STATE, "sg_dealloc_attachments(): attachments must be in ALLOC state") \ _SG_LOGITEM_XMACRO(INIT_BUFFER_INVALID_STATE, "sg_init_buffer(): buffer must be in ALLOC state") \ _SG_LOGITEM_XMACRO(INIT_IMAGE_INVALID_STATE, "sg_init_image(): image must be in ALLOC state") \ _SG_LOGITEM_XMACRO(INIT_SAMPLER_INVALID_STATE, "sg_init_sampler(): sampler must be in ALLOC state") \ _SG_LOGITEM_XMACRO(INIT_SHADER_INVALID_STATE, "sg_init_shader(): shader must be in ALLOC state") \ _SG_LOGITEM_XMACRO(INIT_PIPELINE_INVALID_STATE, "sg_init_pipeline(): pipeline must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(INIT_PASS_INVALID_STATE, "sg_init_pass(): pass must be in ALLOC state") \ + _SG_LOGITEM_XMACRO(INIT_ATTACHMENTS_INVALID_STATE, "sg_init_attachments(): pass must be in ALLOC state") \ _SG_LOGITEM_XMACRO(UNINIT_BUFFER_INVALID_STATE, "sg_uninit_buffer(): buffer must be in VALID or FAILED state") \ _SG_LOGITEM_XMACRO(UNINIT_IMAGE_INVALID_STATE, "sg_uninit_image(): image must be in VALID or FAILED state") \ _SG_LOGITEM_XMACRO(UNINIT_SAMPLER_INVALID_STATE, "sg_uninit_sampler(): sampler must be in VALID or FAILED state") \ _SG_LOGITEM_XMACRO(UNINIT_SHADER_INVALID_STATE, "sg_uninit_shader(): shader must be in VALID or FAILED state") \ _SG_LOGITEM_XMACRO(UNINIT_PIPELINE_INVALID_STATE, "sg_uninit_pipeline(): pipeline must be in VALID or FAILED state") \ - _SG_LOGITEM_XMACRO(UNINIT_PASS_INVALID_STATE, "sg_uninit_pass(): pass must be in VALID or FAILED state") \ + _SG_LOGITEM_XMACRO(UNINIT_ATTACHMENTS_INVALID_STATE, "sg_uninit_attachments(): attachments must be in VALID or FAILED state") \ _SG_LOGITEM_XMACRO(FAIL_BUFFER_INVALID_STATE, "sg_fail_buffer(): buffer must be in ALLOC state") \ _SG_LOGITEM_XMACRO(FAIL_IMAGE_INVALID_STATE, "sg_fail_image(): image must be in ALLOC state") \ _SG_LOGITEM_XMACRO(FAIL_SAMPLER_INVALID_STATE, "sg_fail_sampler(): sampler must be in ALLOC state") \ _SG_LOGITEM_XMACRO(FAIL_SHADER_INVALID_STATE, "sg_fail_shader(): shader must be in ALLOC state") \ _SG_LOGITEM_XMACRO(FAIL_PIPELINE_INVALID_STATE, "sg_fail_pipeline(): pipeline must be in ALLOC state") \ - _SG_LOGITEM_XMACRO(FAIL_PASS_INVALID_STATE, "sg_fail_pass(): pass must be in ALLOC state") \ + _SG_LOGITEM_XMACRO(FAIL_ATTACHMENTS_INVALID_STATE, "sg_fail_attachments(): attachments must be in ALLOC state") \ _SG_LOGITEM_XMACRO(BUFFER_POOL_EXHAUSTED, "buffer pool exhausted") \ _SG_LOGITEM_XMACRO(IMAGE_POOL_EXHAUSTED, "image pool exhausted") \ _SG_LOGITEM_XMACRO(SAMPLER_POOL_EXHAUSTED, "sampler pool exhausted") \ _SG_LOGITEM_XMACRO(SHADER_POOL_EXHAUSTED, "shader pool exhausted") \ _SG_LOGITEM_XMACRO(PIPELINE_POOL_EXHAUSTED, "pipeline pool exhausted") \ _SG_LOGITEM_XMACRO(PASS_POOL_EXHAUSTED, "pass pool exhausted") \ + _SG_LOGITEM_XMACRO(BEGINPASS_ATTACHMENT_INVALID, "sg_begin_pass: an attachment was provided that no longer exists") \ _SG_LOGITEM_XMACRO(DRAW_WITHOUT_BINDINGS, "attempting to draw without resource bindings") \ _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_CANARY, "sg_buffer_desc not initialized") \ _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_SIZE, "sg_buffer_desc.size and .data.size cannot both be 0") \ @@ -3382,46 +3533,78 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_NO_ATTRS, "sg_pipeline_desc.layout.attrs is empty or not continuous") \ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_LAYOUT_STRIDE4, "sg_pipeline_desc.layout.buffers[].stride must be multiple of 4") \ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_ATTR_SEMANTICS, "D3D11 missing vertex attribute semantics in shader") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_CANARY, "sg_pass_desc not initialized") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_NO_ATTACHMENTS, "sg_pass_desc no color or depth-stencil attachments") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_NO_CONT_COLOR_ATTS, "color attachments must occupy continuous slots") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_IMAGE, "pass attachment image is not valid") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_MIPLEVEL, "pass attachment mip level is bigger than image has mipmaps") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_FACE, "pass attachment image is cubemap, but face index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_LAYER, "pass attachment image is array texture, but layer index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_SLICE, "pass attachment image is 3d texture, but slice value is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_IMAGE_NO_RT, "pass attachment image must be have render_target=true") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_COLOR_INV_PIXELFORMAT, "pass color-attachment images must be renderable color pixel format") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_DEPTH_INV_PIXELFORMAT, "pass depth-attachment image must be depth or depth-stencil pixel format") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_IMAGE_SIZES, "all pass attachments must have the same size") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_IMAGE_SAMPLE_COUNTS, "all pass attachments must have the same sample count") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_RESOLVE_COLOR_IMAGE_MSAA, "pass resolve attachments must have a color attachment image with sample count > 1") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_RESOLVE_IMAGE, "pass resolve attachment image not valid") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_RESOLVE_SAMPLE_COUNT, "pass resolve attachment image sample count must be 1") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_RESOLVE_MIPLEVEL, "pass resolve attachment mip level is bigger than image has mipmaps") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_RESOLVE_FACE, "pass resolve attachment is cubemap, but face index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_RESOLVE_LAYER, "pass resolve attachment is array texture, but layer index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_RESOLVE_SLICE, "pass resolve attachment is 3d texture, but slice value is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_RESOLVE_IMAGE_NO_RT, "pass resolve attachment image must have render_target=true") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_RESOLVE_IMAGE_SIZES, "pass resolve attachment size must match color attachment image size") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_RESOLVE_IMAGE_FORMAT, "pass resolve attachment pixel format must match color attachment pixel format") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_DEPTH_IMAGE, "pass depth attachment image is not valid") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_DEPTH_MIPLEVEL, "pass depth attachment mip level is bigger than image has mipmaps") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_DEPTH_FACE, "pass depth attachment image is cubemap, but face index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_DEPTH_LAYER, "pass depth attachment image is array texture, but layer index is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_DEPTH_SLICE, "pass depth attachment image is 3d texture, but slice value is too big") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_DEPTH_IMAGE_NO_RT, "pass depth attachment image must be have render_target=true") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_DEPTH_IMAGE_SIZES, "pass depth attachment image size must match color attachment image size") \ - _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_DEPTH_IMAGE_SAMPLE_COUNT, "pass depth attachment sample count must match color attachment sample count") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_PASS, "sg_begin_pass: pass must be valid") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_CANARY, "sg_attachments_desc not initialized") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_NO_ATTACHMENTS, "sg_attachments_desc no color or depth-stencil attachments") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_NO_CONT_COLOR_ATTS, "color attachments must occupy continuous slots") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_IMAGE, "pass attachment image is not valid") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_MIPLEVEL, "pass attachment mip level is bigger than image has mipmaps") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_FACE, "pass attachment image is cubemap, but face index is too big") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_LAYER, "pass attachment image is array texture, but layer index is too big") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_SLICE, "pass attachment image is 3d texture, but slice value is too big") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_IMAGE_NO_RT, "pass attachment image must be have render_target=true") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_COLOR_INV_PIXELFORMAT, "pass color-attachment images must be renderable color pixel format") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_INV_PIXELFORMAT, "pass depth-attachment image must be depth or depth-stencil pixel format") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_IMAGE_SIZES, "all pass attachments must have the same size") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_IMAGE_SAMPLE_COUNTS, "all pass attachments must have the same sample count") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_COLOR_IMAGE_MSAA, "pass resolve attachments must have a color attachment image with sample count > 1") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE, "pass resolve attachment image not valid") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_SAMPLE_COUNT, "pass resolve attachment image sample count must be 1") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_MIPLEVEL, "pass resolve attachment mip level is bigger than image has mipmaps") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_FACE, "pass resolve attachment is cubemap, but face index is too big") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_LAYER, "pass resolve attachment is array texture, but layer index is too big") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_SLICE, "pass resolve attachment is 3d texture, but slice value is too big") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_NO_RT, "pass resolve attachment image must have render_target=true") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_SIZES, "pass resolve attachment size must match color attachment image size") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_FORMAT, "pass resolve attachment pixel format must match color attachment pixel format") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE, "pass depth attachment image is not valid") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_MIPLEVEL, "pass depth attachment mip level is bigger than image has mipmaps") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_FACE, "pass depth attachment image is cubemap, but face index is too big") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_LAYER, "pass depth attachment image is array texture, but layer index is too big") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_SLICE, "pass depth attachment image is 3d texture, but slice value is too big") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_NO_RT, "pass depth attachment image must be have render_target=true") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SIZES, "pass depth attachment image size must match color attachment image size") \ + _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SAMPLE_COUNT, "pass depth attachment sample count must match color attachment sample count") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_CANARY, "sg_begin_pass: pass struct not initialized") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_ATTACHMENTS_EXISTS, "sg_begin_pass: attachments object no longer alive") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_ATTACHMENTS_VALID, "sg_begin_pass: attachemnts object not in resource state VALID") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE, "sg_begin_pass: one or more color attachment images are not valid") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE, "sg_begin_pass: one or more resolve attachment images are not valid") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE, "sg_begin_pass: one or more depth-stencil attachment images are not valid") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_WIDTH, "sg_begin_pass: expected pass.swapchain.width > 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_WIDTH_NOTSET, "sg_begin_pass: expected pass.swapchain.width == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_HEIGHT, "sg_begin_pass: expected pass.swapchain.height > 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_HEIGHT_NOTSET, "sg_begin_pass: expected pass.swapchain.height == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_SAMPLECOUNT, "sg_begin_pass: expected pass.swapchain.sample_count > 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_SAMPLECOUNT_NOTSET, "sg_begin_pass: expected pass.swapchain.sample_count == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_COLORFORMAT, "sg_begin_pass: expected pass.swapchain.color_format to be valid") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_COLORFORMAT_NOTSET, "sg_begin_pass: expected pass.swapchain.color_format to be unset") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_DEPTHFORMAT_NOTSET, "sg_begin_pass: expected pass.swapchain.depth_format to be unset") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_CURRENTDRAWABLE, "sg_begin_pass: expected pass.swapchain.metal.current_drawable != 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_CURRENTDRAWABLE_NOTSET, "sg_begin_pass: expected pass.swapchain.metal.current_drawable == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_DEPTHSTENCILTEXTURE, "sg_begin_pass: expected pass.swapchain.metal.depth_stencil_texture != 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_DEPTHSTENCILTEXTURE_NOTSET, "sg_begin_pass: expected pass.swapchain.metal.depth_stencil_texture == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_MSAACOLORTEXTURE, "sg_begin_pass: expected pass.swapchain.metal.msaa_color_texture != 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_MSAACOLORTEXTURE_NOTSET, "sg_begin_pass: expected pass.swapchain.metal.msaa_color_texture == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RENDERVIEW, "sg_begin_pass: expected pass.swapchain.d3d11.render_view != 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RENDERVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.d3d11.render_view == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RESOLVEVIEW, "sg_begin_pass: expected pass.swapchain.d3d11.resolve_view != 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RESOLVEVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.d3d11.resolve_view == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_DEPTHSTENCILVIEW, "sg_begin_pass: expected pass.swapchain.d3d11.depth_stencil_view != 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_DEPTHSTENCILVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.d3d11.depth_stencil_view == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RENDERVIEW, "sg_begin_pass: expected pass.swapchain.wgpu.render_view != 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RENDERVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.wgpu.render_view == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RESOLVEVIEW, "sg_begin_pass: expected pass.swapchain.wgpu.resolve_view != 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RESOLVEVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.wgpu.resolve_view == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_DEPTHSTENCILVIEW, "sg_begin_pass: expected pass.swapchain.wgpu.depth_stencil_view != 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_DEPTHSTENCILVIEW_NOTSET, "sg_begin_pass: expected pass.swapchain.wgpu.depth_stencil_view == 0") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_SWAPCHAIN_GL_EXPECT_FRAMEBUFFER_NOTSET, "sg_begin_pass: expected pass.swapchain.gl.framebuffer == 0") \ _SG_LOGITEM_XMACRO(VALIDATE_APIP_PIPELINE_VALID_ID, "sg_apply_pipeline: invalid pipeline id provided") \ _SG_LOGITEM_XMACRO(VALIDATE_APIP_PIPELINE_EXISTS, "sg_apply_pipeline: pipeline object no longer alive") \ _SG_LOGITEM_XMACRO(VALIDATE_APIP_PIPELINE_VALID, "sg_apply_pipeline: pipeline object not in valid state") \ _SG_LOGITEM_XMACRO(VALIDATE_APIP_SHADER_EXISTS, "sg_apply_pipeline: shader object no longer alive") \ _SG_LOGITEM_XMACRO(VALIDATE_APIP_SHADER_VALID, "sg_apply_pipeline: shader object not in valid state") \ + _SG_LOGITEM_XMACRO(VALIDATE_APIP_CURPASS_ATTACHMENTS_EXISTS, "sg_apply_pipeline: current pass attachments no longer alive") \ + _SG_LOGITEM_XMACRO(VALIDATE_APIP_CURPASS_ATTACHMENTS_VALID, "sg_apply_pipeline: current pass attachments not in valid state") \ _SG_LOGITEM_XMACRO(VALIDATE_APIP_ATT_COUNT, "sg_apply_pipeline: number of pipeline color attachments doesn't match number of pass color attachments") \ _SG_LOGITEM_XMACRO(VALIDATE_APIP_COLOR_FORMAT, "sg_apply_pipeline: pipeline color attachment pixel format doesn't match pass color attachment pixel format") \ _SG_LOGITEM_XMACRO(VALIDATE_APIP_DEPTH_FORMAT, "sg_apply_pipeline: pipeline depth pixel_format doesn't match pass depth attachment pixel format") \ @@ -3495,8 +3678,6 @@ typedef enum sg_log_item { either initialize one or the other depending on whether you pass data to your callbacks. - FIXME: explain the various configuration options - The default configuration is: .buffer_pool_size 128 @@ -3505,7 +3686,6 @@ typedef enum sg_log_item { .shader_pool_size 32 .pipeline_pool_size 64 .pass_pool_size 16 - .context_pool_size 16 .uniform_buffer_size 4 MB (4*1024*1024) .max_commit_listeners 1024 .disable_validation false @@ -3517,12 +3697,12 @@ typedef enum sg_log_item { .allocator.free_fn 0 (in this case, free() will be called) .allocator.user_data 0 - .context.color_format: default value depends on selected backend: + .environment.defaults.color_format: default value depends on selected backend: all GL backends: SG_PIXELFORMAT_RGBA8 Metal and D3D11: SG_PIXELFORMAT_BGRA8 - WebGPU: *no default* (must be queried from swapchain) - .context.depth_format SG_PIXELFORMAT_DEPTH_STENCIL - .context.sample_count 1 + WebGPU: *no default* (must be queried from WebGPU swapchain object) + .environment.defaults.depth_format: SG_PIXELFORMAT_DEPTH_STENCIL + .environment.defaults.sample_count: 1 Metal specific: (NOTE: All Objective-C object references are transferred through @@ -3536,43 +3716,21 @@ typedef enum sg_log_item { when enabled, Metal buffers and texture resources are created in managed storage mode, otherwise sokol-gfx will decide whether to create buffers and textures in managed or shared storage mode (this is mainly a debugging option) - .context.metal.device + .mtl_use_command_buffer_with_retained_references + when true, the sokol-gfx Metal backend will use Metal command buffers which + bump the reference count of resource objects as long as they are inflight, + this is slower than the default command-buffer-with-unretained-references + method, this may be a workaround when confronted with lifetime validation + errors from the Metal validation layer until a proper fix has been implemented + .environment.metal.device a pointer to the MTLDevice object - .context.metal.renderpass_descriptor_cb - .context.metal_renderpass_descriptor_userdata_cb - A C callback function to obtain the MTLRenderPassDescriptor for the - current frame when rendering to the default framebuffer, will be called - in sg_begin_default_pass(). - .context.metal.drawable_cb - .context.metal.drawable_userdata_cb - a C callback function to obtain a MTLDrawable for the current - frame when rendering to the default framebuffer, will be called in - sg_end_pass() of the default pass - .context.metal.user_data - optional user data pointer passed to the userdata versions of - callback functions D3D11 specific: - .context.d3d11.device + .environment.d3d11.device a pointer to the ID3D11Device object, this must have been created before sg_setup() is called - .context.d3d11.device_context + .environment.d3d11.device_context a pointer to the ID3D11DeviceContext object - .context.d3d11.render_target_view_cb - .context.d3d11.render_target_view_userdata_cb - a C callback function to obtain a pointer to the current - ID3D11RenderTargetView object of the default framebuffer, - this function will be called in sg_begin_pass() when rendering - to the default framebuffer - .context.d3d11.depth_stencil_view_cb - .context.d3d11.depth_stencil_view_userdata_cb - a C callback function to obtain a pointer to the current - ID3D11DepthStencilView object of the default framebuffer, - this function will be called in sg_begin_pass() when rendering - to the default framebuffer - .context.d3d11.user_data - optional user data pointer passed to the userdata versions of - callback functions WebGPU specific: .wgpu_disable_bindgroups_cache @@ -3588,77 +3746,40 @@ typedef enum sg_log_item { if this is a frequent occurrence, and increase the cache size as needed (the default is 1024). NOTE: wgpu_bindgroups_cache_size must be a power-of-2 number! - .context.wgpu.device + .environment.wgpu.device a WGPUDevice handle - .context.wgpu.render_format - WGPUTextureFormat of the swap chain surface - .context.wgpu.render_view_cb - .context.wgpu.render_view_userdata_cb - callback to get the current WGPUTextureView of the swapchain's - rendering attachment (may be an MSAA surface) - .context.wgpu.resolve_view_cb - .context.wgpu.resolve_view_userdata_cb - callback to get the current WGPUTextureView of the swapchain's - MSAA-resolve-target surface, must return 0 if not MSAA rendering - .context.wgpu.depth_stencil_view_cb - .context.wgpu.depth_stencil_view_userdata_cb - callback to get current default-pass depth-stencil-surface WGPUTextureView - the pixel format of the default WGPUTextureView must be WGPUTextureFormat_Depth32FloatStencil8 - .context.wgpu.user_data - optional user data pointer passed to the userdata versions of - callback functions When using sokol_gfx.h and sokol_app.h together, consider using the - helper function sapp_sgcontext() in the sokol_glue.h header to - initialize the sg_desc.context nested struct. sapp_sgcontext() returns - a completely initialized sg_context_desc struct with information + helper function sglue_environment() in the sokol_glue.h header to + initialize the sg_desc.environment nested struct. sglue_environment() returns + a completely initialized sg_environment struct with information provided by sokol_app.h. */ -typedef struct sg_metal_context_desc { +typedef struct sg_environment_defaults { + sg_pixel_format color_format; + sg_pixel_format depth_format; + int sample_count; +} sg_environment_defaults; + +typedef struct sg_metal_environment { const void* device; - const void* (*renderpass_descriptor_cb)(void); - const void* (*renderpass_descriptor_userdata_cb)(void*); - const void* (*drawable_cb)(void); - const void* (*drawable_userdata_cb)(void*); - void* user_data; -} sg_metal_context_desc; +} sg_metal_environment; -typedef struct sg_d3d11_context_desc { +typedef struct sg_d3d11_environment { const void* device; const void* device_context; - const void* (*render_target_view_cb)(void); - const void* (*render_target_view_userdata_cb)(void*); - const void* (*depth_stencil_view_cb)(void); - const void* (*depth_stencil_view_userdata_cb)(void*); - void* user_data; -} sg_d3d11_context_desc; +} sg_d3d11_environment; -typedef struct sg_wgpu_context_desc { +typedef struct sg_wgpu_environment { const void* device; // WGPUDevice - const void* (*render_view_cb)(void); // returns WGPUTextureView - const void* (*render_view_userdata_cb)(void*); - const void* (*resolve_view_cb)(void); // returns WGPUTextureView - const void* (*resolve_view_userdata_cb)(void*); - const void* (*depth_stencil_view_cb)(void); // returns WGPUTextureView - const void* (*depth_stencil_view_userdata_cb)(void*); - void* user_data; -} sg_wgpu_context_desc; - -typedef struct sg_gl_context_desc { - uint32_t (*default_framebuffer_cb)(void); - uint32_t (*default_framebuffer_userdata_cb)(void*); - void* user_data; -} sg_gl_context_desc; +} sg_wgpu_environment; -typedef struct sg_context_desc { - sg_pixel_format color_format; - sg_pixel_format depth_format; - int sample_count; - sg_metal_context_desc metal; - sg_d3d11_context_desc d3d11; - sg_wgpu_context_desc wgpu; - sg_gl_context_desc gl; -} sg_context_desc; +typedef struct sg_environment { + sg_environment_defaults defaults; + sg_metal_environment metal; + sg_d3d11_environment d3d11; + sg_wgpu_environment wgpu; +} sg_environment; /* sg_commit_listener @@ -3717,17 +3838,17 @@ typedef struct sg_desc { int sampler_pool_size; int shader_pool_size; int pipeline_pool_size; - int pass_pool_size; - int context_pool_size; + int attachments_pool_size; int uniform_buffer_size; int max_commit_listeners; bool disable_validation; // disable validation layer even in debug mode, useful for tests bool mtl_force_managed_storage_mode; // for debugging: use Metal managed storage mode for resources even with UMA + bool mtl_use_command_buffer_with_retained_references; // Metal: use a managed MTLCommandBuffer which ref-counts used resources bool wgpu_disable_bindgroups_cache; // set to true to disable the WebGPU backend BindGroup cache int wgpu_bindgroups_cache_size; // number of slots in the WebGPU bindgroup cache (must be 2^N) sg_allocator allocator; sg_logger logger; // optional log function override - sg_context_desc context; + sg_environment environment; uint32_t _end_canary; } sg_desc; @@ -3748,13 +3869,13 @@ SOKOL_GFX_API_DECL sg_image sg_make_image(const sg_image_desc* desc); SOKOL_GFX_API_DECL sg_sampler sg_make_sampler(const sg_sampler_desc* desc); SOKOL_GFX_API_DECL sg_shader sg_make_shader(const sg_shader_desc* desc); SOKOL_GFX_API_DECL sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc); -SOKOL_GFX_API_DECL sg_pass sg_make_pass(const sg_pass_desc* desc); +SOKOL_GFX_API_DECL sg_attachments sg_make_attachments(const sg_attachments_desc* desc); SOKOL_GFX_API_DECL void sg_destroy_buffer(sg_buffer buf); SOKOL_GFX_API_DECL void sg_destroy_image(sg_image img); SOKOL_GFX_API_DECL void sg_destroy_sampler(sg_sampler smp); SOKOL_GFX_API_DECL void sg_destroy_shader(sg_shader shd); SOKOL_GFX_API_DECL void sg_destroy_pipeline(sg_pipeline pip); -SOKOL_GFX_API_DECL void sg_destroy_pass(sg_pass pass); +SOKOL_GFX_API_DECL void sg_destroy_attachments(sg_attachments atts); SOKOL_GFX_API_DECL void sg_update_buffer(sg_buffer buf, const sg_range* data); SOKOL_GFX_API_DECL void sg_update_image(sg_image img, const sg_image_data* data); SOKOL_GFX_API_DECL int sg_append_buffer(sg_buffer buf, const sg_range* data); @@ -3762,9 +3883,7 @@ SOKOL_GFX_API_DECL bool sg_query_buffer_overflow(sg_buffer buf); SOKOL_GFX_API_DECL bool sg_query_buffer_will_overflow(sg_buffer buf, size_t size); // rendering functions -SOKOL_GFX_API_DECL void sg_begin_default_pass(const sg_pass_action* pass_action, int width, int height); -SOKOL_GFX_API_DECL void sg_begin_default_passf(const sg_pass_action* pass_action, float width, float height); -SOKOL_GFX_API_DECL void sg_begin_pass(sg_pass pass, const sg_pass_action* pass_action); +SOKOL_GFX_API_DECL void sg_begin_pass(const sg_pass* pass); SOKOL_GFX_API_DECL void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left); SOKOL_GFX_API_DECL void sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left); SOKOL_GFX_API_DECL void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left); @@ -3790,28 +3909,28 @@ SOKOL_GFX_API_DECL sg_resource_state sg_query_image_state(sg_image img); SOKOL_GFX_API_DECL sg_resource_state sg_query_sampler_state(sg_sampler smp); SOKOL_GFX_API_DECL sg_resource_state sg_query_shader_state(sg_shader shd); SOKOL_GFX_API_DECL sg_resource_state sg_query_pipeline_state(sg_pipeline pip); -SOKOL_GFX_API_DECL sg_resource_state sg_query_pass_state(sg_pass pass); +SOKOL_GFX_API_DECL sg_resource_state sg_query_attachments_state(sg_attachments atts); // get runtime information about a resource SOKOL_GFX_API_DECL sg_buffer_info sg_query_buffer_info(sg_buffer buf); SOKOL_GFX_API_DECL sg_image_info sg_query_image_info(sg_image img); SOKOL_GFX_API_DECL sg_sampler_info sg_query_sampler_info(sg_sampler smp); SOKOL_GFX_API_DECL sg_shader_info sg_query_shader_info(sg_shader shd); SOKOL_GFX_API_DECL sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip); -SOKOL_GFX_API_DECL sg_pass_info sg_query_pass_info(sg_pass pass); +SOKOL_GFX_API_DECL sg_attachments_info sg_query_attachments_info(sg_attachments atts); // get desc structs matching a specific resource (NOTE that not all creation attributes may be provided) SOKOL_GFX_API_DECL sg_buffer_desc sg_query_buffer_desc(sg_buffer buf); SOKOL_GFX_API_DECL sg_image_desc sg_query_image_desc(sg_image img); SOKOL_GFX_API_DECL sg_sampler_desc sg_query_sampler_desc(sg_sampler smp); SOKOL_GFX_API_DECL sg_shader_desc sg_query_shader_desc(sg_shader shd); SOKOL_GFX_API_DECL sg_pipeline_desc sg_query_pipeline_desc(sg_pipeline pip); -SOKOL_GFX_API_DECL sg_pass_desc sg_query_pass_desc(sg_pass pass); +SOKOL_GFX_API_DECL sg_attachments_desc sg_query_attachments_desc(sg_attachments atts); // get resource creation desc struct with their default values replaced SOKOL_GFX_API_DECL sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc); SOKOL_GFX_API_DECL sg_image_desc sg_query_image_defaults(const sg_image_desc* desc); SOKOL_GFX_API_DECL sg_sampler_desc sg_query_sampler_defaults(const sg_sampler_desc* desc); SOKOL_GFX_API_DECL sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc); SOKOL_GFX_API_DECL sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc); -SOKOL_GFX_API_DECL sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc); +SOKOL_GFX_API_DECL sg_attachments_desc sg_query_attachments_defaults(const sg_attachments_desc* desc); // separate resource allocation and initialization (for async setup) SOKOL_GFX_API_DECL sg_buffer sg_alloc_buffer(void); @@ -3819,31 +3938,31 @@ SOKOL_GFX_API_DECL sg_image sg_alloc_image(void); SOKOL_GFX_API_DECL sg_sampler sg_alloc_sampler(void); SOKOL_GFX_API_DECL sg_shader sg_alloc_shader(void); SOKOL_GFX_API_DECL sg_pipeline sg_alloc_pipeline(void); -SOKOL_GFX_API_DECL sg_pass sg_alloc_pass(void); +SOKOL_GFX_API_DECL sg_attachments sg_alloc_attachments(void); SOKOL_GFX_API_DECL void sg_dealloc_buffer(sg_buffer buf); SOKOL_GFX_API_DECL void sg_dealloc_image(sg_image img); SOKOL_GFX_API_DECL void sg_dealloc_sampler(sg_sampler smp); SOKOL_GFX_API_DECL void sg_dealloc_shader(sg_shader shd); SOKOL_GFX_API_DECL void sg_dealloc_pipeline(sg_pipeline pip); -SOKOL_GFX_API_DECL void sg_dealloc_pass(sg_pass pass); +SOKOL_GFX_API_DECL void sg_dealloc_attachments(sg_attachments attachments); SOKOL_GFX_API_DECL void sg_init_buffer(sg_buffer buf, const sg_buffer_desc* desc); SOKOL_GFX_API_DECL void sg_init_image(sg_image img, const sg_image_desc* desc); SOKOL_GFX_API_DECL void sg_init_sampler(sg_sampler smg, const sg_sampler_desc* desc); SOKOL_GFX_API_DECL void sg_init_shader(sg_shader shd, const sg_shader_desc* desc); SOKOL_GFX_API_DECL void sg_init_pipeline(sg_pipeline pip, const sg_pipeline_desc* desc); -SOKOL_GFX_API_DECL void sg_init_pass(sg_pass pass, const sg_pass_desc* desc); +SOKOL_GFX_API_DECL void sg_init_attachments(sg_attachments attachments, const sg_attachments_desc* desc); SOKOL_GFX_API_DECL void sg_uninit_buffer(sg_buffer buf); SOKOL_GFX_API_DECL void sg_uninit_image(sg_image img); SOKOL_GFX_API_DECL void sg_uninit_sampler(sg_sampler smp); SOKOL_GFX_API_DECL void sg_uninit_shader(sg_shader shd); SOKOL_GFX_API_DECL void sg_uninit_pipeline(sg_pipeline pip); -SOKOL_GFX_API_DECL void sg_uninit_pass(sg_pass pass); +SOKOL_GFX_API_DECL void sg_uninit_attachments(sg_attachments atts); SOKOL_GFX_API_DECL void sg_fail_buffer(sg_buffer buf); SOKOL_GFX_API_DECL void sg_fail_image(sg_image img); SOKOL_GFX_API_DECL void sg_fail_sampler(sg_sampler smp); SOKOL_GFX_API_DECL void sg_fail_shader(sg_shader shd); SOKOL_GFX_API_DECL void sg_fail_pipeline(sg_pipeline pip); -SOKOL_GFX_API_DECL void sg_fail_pass(sg_pass pass); +SOKOL_GFX_API_DECL void sg_fail_attachments(sg_attachments atts); // frame stats SOKOL_GFX_API_DECL void sg_enable_frame_stats(void); @@ -3851,11 +3970,6 @@ SOKOL_GFX_API_DECL void sg_disable_frame_stats(void); SOKOL_GFX_API_DECL bool sg_frame_stats_enabled(void); SOKOL_GFX_API_DECL sg_frame_stats sg_query_frame_stats(void); -// rendering contexts (optional) -SOKOL_GFX_API_DECL sg_context sg_setup_context(void); -SOKOL_GFX_API_DECL void sg_activate_context(sg_context ctx_id); -SOKOL_GFX_API_DECL void sg_discard_context(sg_context ctx_id); - /* Backend-specific structs and functions, these may come in handy for mixing sokol-gfx rendering with 'native backend' rendering functions. @@ -3891,11 +4005,11 @@ typedef struct sg_d3d11_pipeline_info { const void* bs; // ID3D11BlendState* } sg_d3d11_pipeline_info; -typedef struct sg_d3d11_pass_info { +typedef struct sg_d3d11_attachments_info { const void* color_rtv[SG_MAX_COLOR_ATTACHMENTS]; // ID3D11RenderTargetView const void* resolve_rtv[SG_MAX_COLOR_ATTACHMENTS]; // ID3D11RenderTargetView const void* dsv; // ID3D11DepthStencilView -} sg_d3d11_pass_info; +} sg_d3d11_attachments_info; typedef struct sg_mtl_buffer_info { const void* buf[SG_NUM_INFLIGHT_FRAMES]; // id @@ -3946,11 +4060,11 @@ typedef struct sg_wgpu_pipeline_info { const void* pip; // WGPURenderPipeline } sg_wgpu_pipeline_info; -typedef struct sg_wgpu_pass_info { +typedef struct sg_wgpu_attachments_info { const void* color_view[SG_MAX_COLOR_ATTACHMENTS]; // WGPUTextureView const void* resolve_view[SG_MAX_COLOR_ATTACHMENTS]; // WGPUTextureView const void* ds_view; // WGPUTextureView -} sg_wgpu_pass_info; +} sg_wgpu_attachments_info; typedef struct sg_gl_buffer_info { uint32_t buf[SG_NUM_INFLIGHT_FRAMES]; @@ -3972,10 +4086,10 @@ typedef struct sg_gl_shader_info { uint32_t prog; } sg_gl_shader_info; -typedef struct sg_gl_pass_info { - uint32_t frame_buffer; +typedef struct sg_gl_attachments_info { + uint32_t framebuffer; uint32_t msaa_resolve_framebuffer[SG_MAX_COLOR_ATTACHMENTS]; -} sg_gl_pass_info; +} sg_gl_attachments_info; // D3D11: return ID3D11Device SOKOL_GFX_API_DECL const void* sg_d3d11_device(void); @@ -3992,7 +4106,7 @@ SOKOL_GFX_API_DECL sg_d3d11_shader_info sg_d3d11_query_shader_info(sg_shader shd // D3D11: get internal pipeline resource objects SOKOL_GFX_API_DECL sg_d3d11_pipeline_info sg_d3d11_query_pipeline_info(sg_pipeline pip); // D3D11: get internal pass resource objects -SOKOL_GFX_API_DECL sg_d3d11_pass_info sg_d3d11_query_pass_info(sg_pass pass); +SOKOL_GFX_API_DECL sg_d3d11_attachments_info sg_d3d11_query_attachments_info(sg_attachments atts); // Metal: return __bridge-casted MTLDevice SOKOL_GFX_API_DECL const void* sg_mtl_device(void); @@ -4028,7 +4142,7 @@ SOKOL_GFX_API_DECL sg_wgpu_shader_info sg_wgpu_query_shader_info(sg_shader shd); // WebGPU: get internal pipeline resource objects SOKOL_GFX_API_DECL sg_wgpu_pipeline_info sg_wgpu_query_pipeline_info(sg_pipeline pip); // WebGPU: get internal pass resource objects -SOKOL_GFX_API_DECL sg_wgpu_pass_info sg_wgpu_query_pass_info(sg_pass pass); +SOKOL_GFX_API_DECL sg_wgpu_attachments_info sg_wgpu_query_attachments_info(sg_attachments atts); // GL: get internal buffer resource objects SOKOL_GFX_API_DECL sg_gl_buffer_info sg_gl_query_buffer_info(sg_buffer buf); @@ -4039,7 +4153,7 @@ SOKOL_GFX_API_DECL sg_gl_sampler_info sg_gl_query_sampler_info(sg_sampler smp); // GL: get internal shader resource objects SOKOL_GFX_API_DECL sg_gl_shader_info sg_gl_query_shader_info(sg_shader shd); // GL: get internal pass resource objects -SOKOL_GFX_API_DECL sg_gl_pass_info sg_gl_query_pass_info(sg_pass pass); +SOKOL_GFX_API_DECL sg_gl_attachments_info sg_gl_query_attachments_info(sg_attachments atts); #ifdef __cplusplus } // extern "C" @@ -4052,12 +4166,10 @@ inline sg_image sg_make_image(const sg_image_desc& desc) { return sg_make_image( inline sg_sampler sg_make_sampler(const sg_sampler_desc& desc) { return sg_make_sampler(&desc); } inline sg_shader sg_make_shader(const sg_shader_desc& desc) { return sg_make_shader(&desc); } inline sg_pipeline sg_make_pipeline(const sg_pipeline_desc& desc) { return sg_make_pipeline(&desc); } -inline sg_pass sg_make_pass(const sg_pass_desc& desc) { return sg_make_pass(&desc); } +inline sg_attachments sg_make_attchments(const sg_attachments_desc& desc) { return sg_make_attachments(&desc); } inline void sg_update_image(sg_image img, const sg_image_data& data) { return sg_update_image(img, &data); } -inline void sg_begin_default_pass(const sg_pass_action& pass_action, int width, int height) { return sg_begin_default_pass(&pass_action, width, height); } -inline void sg_begin_default_passf(const sg_pass_action& pass_action, float width, float height) { return sg_begin_default_passf(&pass_action, width, height); } -inline void sg_begin_pass(sg_pass pass, const sg_pass_action& pass_action) { return sg_begin_pass(pass, &pass_action); } +inline void sg_begin_pass(const sg_pass& pass) { return sg_begin_pass(&pass); } inline void sg_apply_bindings(const sg_bindings& bindings) { return sg_apply_bindings(&bindings); } inline void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range& data) { return sg_apply_uniforms(stage, ub_index, &data); } @@ -4066,14 +4178,14 @@ inline sg_image_desc sg_query_image_defaults(const sg_image_desc& desc) { return inline sg_sampler_desc sg_query_sampler_defaults(const sg_sampler_desc& desc) { return sg_query_sampler_defaults(&desc); } inline sg_shader_desc sg_query_shader_defaults(const sg_shader_desc& desc) { return sg_query_shader_defaults(&desc); } inline sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc& desc) { return sg_query_pipeline_defaults(&desc); } -inline sg_pass_desc sg_query_pass_defaults(const sg_pass_desc& desc) { return sg_query_pass_defaults(&desc); } +inline sg_attachments_desc sg_query_attachments_defaults(const sg_attachments_desc& desc) { return sg_query_attachments_defaults(&desc); } inline void sg_init_buffer(sg_buffer buf, const sg_buffer_desc& desc) { return sg_init_buffer(buf, &desc); } inline void sg_init_image(sg_image img, const sg_image_desc& desc) { return sg_init_image(img, &desc); } inline void sg_init_sampler(sg_sampler smp, const sg_sampler_desc& desc) { return sg_init_sampler(smp, &desc); } inline void sg_init_shader(sg_shader shd, const sg_shader_desc& desc) { return sg_init_shader(shd, &desc); } inline void sg_init_pipeline(sg_pipeline pip, const sg_pipeline_desc& desc) { return sg_init_pipeline(pip, &desc); } -inline void sg_init_pass(sg_pass pass, const sg_pass_desc& desc) { return sg_init_pass(pass, &desc); } +inline void sg_init_attachments(sg_attachments atts, const sg_attachments_desc& desc) { return sg_init_attachments(atts, &desc); } inline void sg_update_buffer(sg_buffer buf_id, const sg_range& data) { return sg_update_buffer(buf_id, &data); } inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_append_buffer(buf_id, &data); } @@ -4202,6 +4314,7 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #endif #endif #import + #import // needed for CAMetalDrawable #elif defined(SOKOL_WGPU) #include #if defined(__EMSCRIPTEN__) @@ -4240,8 +4353,13 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #include #endif #elif defined(__linux__) || defined(__unix__) - #define GL_GLEXT_PROTOTYPES - #include + #if defined(SOKOL_GLCORE33) + #define GL_GLEXT_PROTOTYPES + #include + #else + #include + #include + #endif #endif #endif @@ -4479,7 +4597,7 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #define GL_CLAMP_TO_BORDER 0x812D #define GL_TEXTURE_BORDER_COLOR 0x1004 #define GL_CURRENT_PROGRAM 0x8B8D - #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB + #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_FRAMEBUFFER_SRGB 0x8DB9 #define GL_TEXTURE_COMPARE_MODE 0x884C @@ -4598,6 +4716,15 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #endif #endif +#if defined(SOKOL_GLES3) + // on WebGL2, GL_FRAMEBUFFER_UNDEFINED technically doesn't exist (it is defined + // in the Emscripten headers, but may not exist in other WebGL2 shims) + // see: https://github.com/floooh/sokol/pull/933 + #ifndef GL_FRAMEBUFFER_UNDEFINED + #define GL_FRAMEBUFFER_UNDEFINED 0x8219 + #endif +#endif + // ███████ ████████ ██████ ██ ██ ██████ ████████ ███████ // ██ ██ ██ ██ ██ ██ ██ ██ ██ // ███████ ██ ██████ ██ ██ ██ ██ ███████ @@ -4608,7 +4735,6 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ // resource pool slots typedef struct { uint32_t id; - uint32_t ctx_id; sg_resource_state state; } _sg_slot_t; @@ -4639,8 +4765,7 @@ enum { _SG_DEFAULT_SAMPLER_POOL_SIZE = 64, _SG_DEFAULT_SHADER_POOL_SIZE = 32, _SG_DEFAULT_PIPELINE_POOL_SIZE = 64, - _SG_DEFAULT_PASS_POOL_SIZE = 16, - _SG_DEFAULT_CONTEXT_POOL_SIZE = 16, + _SG_DEFAULT_ATTACHMENTS_POOL_SIZE = 16, _SG_DEFAULT_UB_SIZE = 4 * 1024 * 1024, _SG_DEFAULT_MAX_COMMIT_LISTENERS = 1024, _SG_DEFAULT_WGPU_BINDGROUP_CACHE_SIZE = 1024, @@ -4875,36 +5000,36 @@ typedef struct { sg_image image_id; int mip_level; int slice; -} _sg_pass_attachment_common_t; +} _sg_attachment_common_t; typedef struct { int width; int height; - int num_color_atts; - _sg_pass_attachment_common_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_pass_attachment_common_t resolve_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_pass_attachment_common_t ds_att; -} _sg_pass_common_t; + int num_colors; + _sg_attachment_common_t colors[SG_MAX_COLOR_ATTACHMENTS]; + _sg_attachment_common_t resolves[SG_MAX_COLOR_ATTACHMENTS]; + _sg_attachment_common_t depth_stencil; +} _sg_attachments_common_t; -_SOKOL_PRIVATE void _sg_pass_attachment_common_init(_sg_pass_attachment_common_t* cmn, const sg_pass_attachment_desc* desc) { +_SOKOL_PRIVATE void _sg_attachment_common_init(_sg_attachment_common_t* cmn, const sg_attachment_desc* desc) { cmn->image_id = desc->image; cmn->mip_level = desc->mip_level; cmn->slice = desc->slice; } -_SOKOL_PRIVATE void _sg_pass_common_init(_sg_pass_common_t* cmn, const sg_pass_desc* desc, int width, int height) { +_SOKOL_PRIVATE void _sg_attachments_common_init(_sg_attachments_common_t* cmn, const sg_attachments_desc* desc, int width, int height) { SOKOL_ASSERT((width > 0) && (height > 0)); cmn->width = width; cmn->height = height; for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (desc->color_attachments[i].image.id != SG_INVALID_ID) { - cmn->num_color_atts++; - _sg_pass_attachment_common_init(&cmn->color_atts[i], &desc->color_attachments[i]); - _sg_pass_attachment_common_init(&cmn->resolve_atts[i], &desc->resolve_attachments[i]); + if (desc->colors[i].image.id != SG_INVALID_ID) { + cmn->num_colors++; + _sg_attachment_common_init(&cmn->colors[i], &desc->colors[i]); + _sg_attachment_common_init(&cmn->resolves[i], &desc->resolves[i]); } } - if (desc->depth_stencil_attachment.image.id != SG_INVALID_ID) { - _sg_pass_attachment_common_init(&cmn->ds_att, &desc->depth_stencil_attachment); + if (desc->depth_stencil.image.id != SG_INVALID_ID) { + _sg_attachment_common_init(&cmn->depth_stencil, &desc->depth_stencil); } } @@ -4946,20 +5071,14 @@ typedef struct { typedef struct { _sg_slot_t slot; - _sg_pass_common_t cmn; + _sg_attachments_common_t cmn; struct { - _sg_dummy_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_dummy_attachment_t resolve_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_dummy_attachment_t ds_att; + _sg_dummy_attachment_t colors[SG_MAX_COLOR_ATTACHMENTS]; + _sg_dummy_attachment_t resolves[SG_MAX_COLOR_ATTACHMENTS]; + _sg_dummy_attachment_t depth_stencil; } dmy; -} _sg_dummy_pass_t; -typedef _sg_dummy_pass_t _sg_pass_t; -typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; - -typedef struct { - _sg_slot_t slot; -} _sg_dummy_context_t; -typedef _sg_dummy_context_t _sg_context_t; +} _sg_dummy_attachments_t; +typedef _sg_dummy_attachments_t _sg_attachments_t; #elif defined(_SOKOL_ANY_GL) typedef struct { @@ -5065,24 +5184,16 @@ typedef struct { typedef struct { _sg_slot_t slot; - _sg_pass_common_t cmn; + _sg_attachments_common_t cmn; struct { GLuint fb; - _sg_gl_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_gl_attachment_t resolve_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_gl_attachment_t ds_att; + _sg_gl_attachment_t colors[SG_MAX_COLOR_ATTACHMENTS]; + _sg_gl_attachment_t resolves[SG_MAX_COLOR_ATTACHMENTS]; + _sg_gl_attachment_t depth_stencil; GLuint msaa_resolve_framebuffer[SG_MAX_COLOR_ATTACHMENTS]; } gl; -} _sg_gl_pass_t; -typedef _sg_gl_pass_t _sg_pass_t; -typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; - -typedef struct { - _sg_slot_t slot; - GLuint vao; - GLuint default_framebuffer; -} _sg_gl_context_t; -typedef _sg_gl_context_t _sg_context_t; +} _sg_gl_attachments_t; +typedef _sg_gl_attachments_t _sg_attachments_t; typedef struct { _sg_gl_attr_t gl_attr; @@ -5126,12 +5237,7 @@ typedef struct { typedef struct { bool valid; - bool in_pass; - int cur_pass_width; - int cur_pass_height; - _sg_context_t* cur_context; - _sg_pass_t* cur_pass; - sg_pass cur_pass_id; + GLuint vao; _sg_gl_state_cache_t cache; bool ext_anisotropic; GLint max_anisotropy; @@ -5226,42 +5332,27 @@ typedef struct { typedef struct { _sg_slot_t slot; - _sg_pass_common_t cmn; + _sg_attachments_common_t cmn; struct { - _sg_d3d11_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_d3d11_attachment_t resolve_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_d3d11_attachment_t ds_att; + _sg_d3d11_attachment_t colors[SG_MAX_COLOR_ATTACHMENTS]; + _sg_d3d11_attachment_t resolves[SG_MAX_COLOR_ATTACHMENTS]; + _sg_d3d11_attachment_t depth_stencil; } d3d11; -} _sg_d3d11_pass_t; -typedef _sg_d3d11_pass_t _sg_pass_t; -typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; - -typedef struct { - _sg_slot_t slot; -} _sg_d3d11_context_t; -typedef _sg_d3d11_context_t _sg_context_t; +} _sg_d3d11_attachments_t; +typedef _sg_d3d11_attachments_t _sg_attachments_t; typedef struct { bool valid; ID3D11Device* dev; ID3D11DeviceContext* ctx; - const void* (*rtv_cb)(void); - const void* (*rtv_userdata_cb)(void*); - const void* (*dsv_cb)(void); - const void* (*dsv_userdata_cb)(void*); - void* user_data; - bool in_pass; bool use_indexed_draw; bool use_instanced_draw; - int cur_width; - int cur_height; - int num_rtvs; - _sg_pass_t* cur_pass; - sg_pass cur_pass_id; _sg_pipeline_t* cur_pipeline; sg_pipeline cur_pipeline_id; - ID3D11RenderTargetView* cur_rtvs[SG_MAX_COLOR_ATTACHMENTS]; - ID3D11DepthStencilView* cur_dsv; + struct { + ID3D11RenderTargetView* render_view; + ID3D11RenderTargetView* resolve_view; + } cur_pass; // on-demand loaded d3dcompiler_47.dll handles HINSTANCE d3dcompiler_dll; bool d3dcompiler_dll_load_failed; @@ -5358,28 +5449,22 @@ typedef struct { typedef struct { _sg_slot_t slot; - _sg_pass_common_t cmn; + _sg_attachments_common_t cmn; struct { - _sg_mtl_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_mtl_attachment_t resolve_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_mtl_attachment_t ds_att; + _sg_mtl_attachment_t colors[SG_MAX_COLOR_ATTACHMENTS]; + _sg_mtl_attachment_t resolves[SG_MAX_COLOR_ATTACHMENTS]; + _sg_mtl_attachment_t depth_stencil; } mtl; -} _sg_mtl_pass_t; -typedef _sg_mtl_pass_t _sg_pass_t; -typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; - -typedef struct { - _sg_slot_t slot; -} _sg_mtl_context_t; -typedef _sg_mtl_context_t _sg_context_t; +} _sg_mtl_attachments_t; +typedef _sg_mtl_attachments_t _sg_attachments_t; // resource binding state cache typedef struct { const _sg_pipeline_t* cur_pipeline; sg_pipeline cur_pipeline_id; const _sg_buffer_t* cur_indexbuffer; - int cur_indexbuffer_offset; sg_buffer cur_indexbuffer_id; + int cur_indexbuffer_offset; int cur_vertexbuffer_offsets[SG_MAX_VERTEX_BUFFERS]; sg_buffer cur_vertexbuffer_ids[SG_MAX_VERTEX_BUFFERS]; sg_image cur_vs_image_ids[SG_MAX_SHADERSTAGE_IMAGES]; @@ -5391,19 +5476,10 @@ typedef struct { typedef struct { bool valid; bool use_shared_storage_mode; - const void*(*renderpass_descriptor_cb)(void); - const void*(*renderpass_descriptor_userdata_cb)(void*); - const void*(*drawable_cb)(void); - const void*(*drawable_userdata_cb)(void*); - void* user_data; uint32_t cur_frame_rotate_index; int ub_size; int cur_ub_offset; uint8_t* cur_ub_base_ptr; - bool in_pass; - bool pass_valid; - int cur_width; - int cur_height; _sg_mtl_state_cache_t state_cache; _sg_mtl_idpool_t idpool; dispatch_semaphore_t sem; @@ -5411,6 +5487,7 @@ typedef struct { id cmd_queue; id cmd_buffer; id cmd_encoder; + id cur_drawable; id uniform_buffers[SG_NUM_INFLIGHT_FRAMES]; } _sg_mtl_backend_t; @@ -5483,20 +5560,14 @@ typedef struct { typedef struct { _sg_slot_t slot; - _sg_pass_common_t cmn; + _sg_attachments_common_t cmn; struct { - _sg_wgpu_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_wgpu_attachment_t resolve_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_wgpu_attachment_t ds_att; + _sg_wgpu_attachment_t colors[SG_MAX_COLOR_ATTACHMENTS]; + _sg_wgpu_attachment_t resolves[SG_MAX_COLOR_ATTACHMENTS]; + _sg_wgpu_attachment_t depth_stencil; } wgpu; -} _sg_wgpu_pass_t; -typedef _sg_wgpu_pass_t _sg_pass_t; -typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; - -typedef struct { - _sg_slot_t slot; -} _sg_wgpu_context_t; -typedef _sg_wgpu_context_t _sg_context_t; +} _sg_wgpu_attachments_t; +typedef _sg_wgpu_attachments_t _sg_attachments_t; // a pool of per-frame uniform buffers typedef struct { @@ -5553,18 +5624,8 @@ typedef struct { // the WGPU backend state typedef struct { bool valid; - WGPUDevice dev; - WGPUTextureView (*render_view_cb)(void); - WGPUTextureView (*render_view_userdata_cb)(void*); - WGPUTextureView (*resolve_view_cb)(void); - WGPUTextureView (*resolve_view_userdata_cb)(void*); - WGPUTextureView (*depth_stencil_view_cb)(void); - WGPUTextureView (*depth_stencil_view_userdata_cb)(void*); - void* user_data; - bool in_pass; bool use_indexed_draw; - int cur_width; - int cur_height; + WGPUDevice dev; WGPUSupportedLimits limits; WGPUQueue queue; WGPUCommandEncoder cmd_enc; @@ -5590,15 +5651,13 @@ typedef struct { _sg_pool_t sampler_pool; _sg_pool_t shader_pool; _sg_pool_t pipeline_pool; - _sg_pool_t pass_pool; - _sg_pool_t context_pool; + _sg_pool_t attachments_pool; _sg_buffer_t* buffers; _sg_image_t* images; _sg_sampler_t* samplers; _sg_shader_t* shaders; _sg_pipeline_t* pipelines; - _sg_pass_t* passes; - _sg_context_t* contexts; + _sg_attachments_t* attachments; } _sg_pools_t; typedef struct { @@ -5638,11 +5697,21 @@ typedef struct { bool valid; sg_desc desc; // original desc with default values patched in uint32_t frame_index; - sg_context active_context; - sg_pass cur_pass; + struct { + bool valid; + bool in_pass; + sg_attachments atts_id; // SG_INVALID_ID in a swapchain pass + _sg_attachments_t* atts; // 0 in a swapchain pass + int width; + int height; + struct { + sg_pixel_format color_fmt; + sg_pixel_format depth_fmt; + int sample_count; + } swapchain; + } cur_pass; sg_pipeline cur_pipeline; - bool pass_valid; - bool bindings_applied; + bool apply_bindings_called; bool next_draw_valid; #if defined(SOKOL_DEBUG) sg_log_item validate_error; @@ -6247,35 +6316,36 @@ _SOKOL_PRIVATE void _sg_pixelformat_sfbr(_sg_pixelformat_info_t* pfi) { pfi->render = true; } -_SOKOL_PRIVATE void _sg_resolve_default_pass_action(const sg_pass_action* from, sg_pass_action* to) { - SOKOL_ASSERT(from && to); - *to = *from; +_SOKOL_PRIVATE sg_pass_action _sg_pass_action_defaults(const sg_pass_action* action) { + SOKOL_ASSERT(action); + sg_pass_action res = *action; for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (to->colors[i].load_action == _SG_LOADACTION_DEFAULT) { - to->colors[i].load_action = SG_LOADACTION_CLEAR; - to->colors[i].clear_value.r = SG_DEFAULT_CLEAR_RED; - to->colors[i].clear_value.g = SG_DEFAULT_CLEAR_GREEN; - to->colors[i].clear_value.b = SG_DEFAULT_CLEAR_BLUE; - to->colors[i].clear_value.a = SG_DEFAULT_CLEAR_ALPHA; + if (res.colors[i].load_action == _SG_LOADACTION_DEFAULT) { + res.colors[i].load_action = SG_LOADACTION_CLEAR; + res.colors[i].clear_value.r = SG_DEFAULT_CLEAR_RED; + res.colors[i].clear_value.g = SG_DEFAULT_CLEAR_GREEN; + res.colors[i].clear_value.b = SG_DEFAULT_CLEAR_BLUE; + res.colors[i].clear_value.a = SG_DEFAULT_CLEAR_ALPHA; } - if (to->colors[i].store_action == _SG_STOREACTION_DEFAULT) { - to->colors[i].store_action = SG_STOREACTION_STORE; + if (res.colors[i].store_action == _SG_STOREACTION_DEFAULT) { + res.colors[i].store_action = SG_STOREACTION_STORE; } } - if (to->depth.load_action == _SG_LOADACTION_DEFAULT) { - to->depth.load_action = SG_LOADACTION_CLEAR; - to->depth.clear_value = SG_DEFAULT_CLEAR_DEPTH; + if (res.depth.load_action == _SG_LOADACTION_DEFAULT) { + res.depth.load_action = SG_LOADACTION_CLEAR; + res.depth.clear_value = SG_DEFAULT_CLEAR_DEPTH; } - if (to->depth.store_action == _SG_STOREACTION_DEFAULT) { - to->depth.store_action = SG_STOREACTION_DONTCARE; + if (res.depth.store_action == _SG_STOREACTION_DEFAULT) { + res.depth.store_action = SG_STOREACTION_DONTCARE; } - if (to->stencil.load_action == _SG_LOADACTION_DEFAULT) { - to->stencil.load_action = SG_LOADACTION_CLEAR; - to->stencil.clear_value = SG_DEFAULT_CLEAR_STENCIL; + if (res.stencil.load_action == _SG_LOADACTION_DEFAULT) { + res.stencil.load_action = SG_LOADACTION_CLEAR; + res.stencil.clear_value = SG_DEFAULT_CLEAR_STENCIL; } - if (to->stencil.store_action == _SG_STOREACTION_DEFAULT) { - to->stencil.store_action = SG_STOREACTION_DONTCARE; + if (res.stencil.store_action == _SG_STOREACTION_DEFAULT) { + res.stencil.store_action = SG_STOREACTION_DONTCARE; } + return res; } // ██████ ██ ██ ███ ███ ███ ███ ██ ██ ██████ █████ ██████ ██ ██ ███████ ███ ██ ██████ @@ -6310,22 +6380,6 @@ _SOKOL_PRIVATE void _sg_dummy_reset_state_cache(void) { // empty } -_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_context(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - _SOKOL_UNUSED(ctx); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_dummy_discard_context(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - _SOKOL_UNUSED(ctx); -} - -_SOKOL_PRIVATE void _sg_dummy_activate_context(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - _SOKOL_UNUSED(ctx); -} - _SOKOL_PRIVATE sg_resource_state _sg_dummy_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { SOKOL_ASSERT(buf && desc); _SOKOL_UNUSED(buf); @@ -6393,64 +6447,61 @@ _SOKOL_PRIVATE void _sg_dummy_discard_pipeline(_sg_pipeline_t* pip) { _SOKOL_UNUSED(pip); } -_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_pass(_sg_pass_t* pass, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_pass_desc* desc) { - SOKOL_ASSERT(pass && desc); +_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_attachments_desc* desc) { + SOKOL_ASSERT(atts && desc); SOKOL_ASSERT(color_images && resolve_images); - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - const sg_pass_attachment_desc* color_desc = &desc->color_attachments[i]; + for (int i = 0; i < atts->cmn.num_colors; i++) { + const sg_attachment_desc* color_desc = &desc->colors[i]; _SOKOL_UNUSED(color_desc); SOKOL_ASSERT(color_desc->image.id != SG_INVALID_ID); - SOKOL_ASSERT(0 == pass->dmy.color_atts[i].image); + SOKOL_ASSERT(0 == atts->dmy.colors[i].image); SOKOL_ASSERT(color_images[i] && (color_images[i]->slot.id == color_desc->image.id)); SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(color_images[i]->cmn.pixel_format)); - pass->dmy.color_atts[i].image = color_images[i]; + atts->dmy.colors[i].image = color_images[i]; - const sg_pass_attachment_desc* resolve_desc = &desc->resolve_attachments[i]; + const sg_attachment_desc* resolve_desc = &desc->resolves[i]; if (resolve_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(0 == pass->dmy.resolve_atts[i].image); + SOKOL_ASSERT(0 == atts->dmy.resolves[i].image); SOKOL_ASSERT(resolve_images[i] && (resolve_images[i]->slot.id == resolve_desc->image.id)); SOKOL_ASSERT(color_images[i] && (color_images[i]->cmn.pixel_format == resolve_images[i]->cmn.pixel_format)); - pass->dmy.resolve_atts[i].image = resolve_images[i]; + atts->dmy.resolves[i].image = resolve_images[i]; } } - SOKOL_ASSERT(0 == pass->dmy.ds_att.image); - const sg_pass_attachment_desc* ds_desc = &desc->depth_stencil_attachment; + SOKOL_ASSERT(0 == atts->dmy.depth_stencil.image); + const sg_attachment_desc* ds_desc = &desc->depth_stencil; if (ds_desc->image.id != SG_INVALID_ID) { SOKOL_ASSERT(ds_img && (ds_img->slot.id == ds_desc->image.id)); SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(ds_img->cmn.pixel_format)); - pass->dmy.ds_att.image = ds_img; + atts->dmy.depth_stencil.image = ds_img; } return SG_RESOURCESTATE_VALID; } -_SOKOL_PRIVATE void _sg_dummy_discard_pass(_sg_pass_t* pass) { - SOKOL_ASSERT(pass); - _SOKOL_UNUSED(pass); +_SOKOL_PRIVATE void _sg_dummy_discard_attachments(_sg_attachments_t* atts) { + SOKOL_ASSERT(atts); + _SOKOL_UNUSED(atts); } -_SOKOL_PRIVATE _sg_image_t* _sg_dummy_pass_color_image(const _sg_pass_t* pass, int index) { - SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return pass->dmy.color_atts[index].image; +_SOKOL_PRIVATE _sg_image_t* _sg_dummy_attachments_color_image(const _sg_attachments_t* atts, int index) { + SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + return atts->dmy.colors[index].image; } -_SOKOL_PRIVATE _sg_image_t* _sg_dummy_pass_resolve_image(const _sg_pass_t* pass, int index) { - SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return pass->dmy.resolve_atts[index].image; +_SOKOL_PRIVATE _sg_image_t* _sg_dummy_attachments_resolve_image(const _sg_attachments_t* atts, int index) { + SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + return atts->dmy.resolves[index].image; } -_SOKOL_PRIVATE _sg_image_t* _sg_dummy_pass_ds_image(const _sg_pass_t* pass) { - SOKOL_ASSERT(pass); - return pass->dmy.ds_att.image; +_SOKOL_PRIVATE _sg_image_t* _sg_dummy_attachments_ds_image(const _sg_attachments_t* atts) { + SOKOL_ASSERT(atts); + return atts->dmy.depth_stencil.image; } -_SOKOL_PRIVATE void _sg_dummy_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { - SOKOL_ASSERT(action); +_SOKOL_PRIVATE void _sg_dummy_begin_pass(const sg_pass* pass) { + SOKOL_ASSERT(pass); _SOKOL_UNUSED(pass); - _SOKOL_UNUSED(action); - _SOKOL_UNUSED(w); - _SOKOL_UNUSED(h); } _SOKOL_PRIVATE void _sg_dummy_end_pass(void) { @@ -7329,9 +7380,9 @@ _SOKOL_PRIVATE void _sg_gl_init_limits(void) { gl_int = SG_MAX_VERTEX_ATTRIBUTES; } _sg.limits.max_vertex_attrs = gl_int; - glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &gl_int); + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &gl_int); _SG_GL_CHECK_ERROR(); - _sg.limits.gl_max_vertex_uniform_vectors = gl_int; + _sg.limits.gl_max_vertex_uniform_components = gl_int; glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gl_int); _SG_GL_CHECK_ERROR(); _sg.limits.max_image_size_3d = gl_int; @@ -7728,90 +7779,87 @@ _SOKOL_PRIVATE void _sg_gl_cache_invalidate_pipeline(_sg_pipeline_t* pip) { } _SOKOL_PRIVATE void _sg_gl_reset_state_cache(void) { - if (_sg.gl.cur_context) { - _SG_GL_CHECK_ERROR(); - glBindVertexArray(_sg.gl.cur_context->vao); - _SG_GL_CHECK_ERROR(); - _sg_clear(&_sg.gl.cache, sizeof(_sg.gl.cache)); - _sg_gl_cache_clear_buffer_bindings(true); - _SG_GL_CHECK_ERROR(); - _sg_gl_cache_clear_texture_sampler_bindings(true); + _SG_GL_CHECK_ERROR(); + glBindVertexArray(_sg.gl.vao); + _SG_GL_CHECK_ERROR(); + _sg_clear(&_sg.gl.cache, sizeof(_sg.gl.cache)); + _sg_gl_cache_clear_buffer_bindings(true); + _SG_GL_CHECK_ERROR(); + _sg_gl_cache_clear_texture_sampler_bindings(true); + _SG_GL_CHECK_ERROR(); + for (int i = 0; i < _sg.limits.max_vertex_attrs; i++) { + _sg_gl_attr_t* attr = &_sg.gl.cache.attrs[i].gl_attr; + attr->vb_index = -1; + attr->divisor = -1; + glDisableVertexAttribArray((GLuint)i); _SG_GL_CHECK_ERROR(); - for (int i = 0; i < _sg.limits.max_vertex_attrs; i++) { - _sg_gl_attr_t* attr = &_sg.gl.cache.attrs[i].gl_attr; - attr->vb_index = -1; - attr->divisor = -1; - glDisableVertexAttribArray((GLuint)i); - _SG_GL_CHECK_ERROR(); - _sg_stats_add(gl.num_disable_vertex_attrib_array, 1); - } - _sg.gl.cache.cur_primitive_type = GL_TRIANGLES; + _sg_stats_add(gl.num_disable_vertex_attrib_array, 1); + } + _sg.gl.cache.cur_primitive_type = GL_TRIANGLES; - // shader program - glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&_sg.gl.cache.prog); - _SG_GL_CHECK_ERROR(); + // shader program + glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&_sg.gl.cache.prog); + _SG_GL_CHECK_ERROR(); - // depth and stencil state - _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS; - _sg.gl.cache.stencil.front.compare = SG_COMPAREFUNC_ALWAYS; - _sg.gl.cache.stencil.front.fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.front.depth_fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.front.pass_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.back.compare = SG_COMPAREFUNC_ALWAYS; - _sg.gl.cache.stencil.back.fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.back.depth_fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.back.pass_op = SG_STENCILOP_KEEP; - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glDepthMask(GL_FALSE); - glDisable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 0, 0); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilMask(0); - _sg_stats_add(gl.num_render_state, 7); - - // blend state - _sg.gl.cache.blend.src_factor_rgb = SG_BLENDFACTOR_ONE; - _sg.gl.cache.blend.dst_factor_rgb = SG_BLENDFACTOR_ZERO; - _sg.gl.cache.blend.op_rgb = SG_BLENDOP_ADD; - _sg.gl.cache.blend.src_factor_alpha = SG_BLENDFACTOR_ONE; - _sg.gl.cache.blend.dst_factor_alpha = SG_BLENDFACTOR_ZERO; - _sg.gl.cache.blend.op_alpha = SG_BLENDOP_ADD; - glDisable(GL_BLEND); - glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); - glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); - _sg_stats_add(gl.num_render_state, 4); - - // standalone state - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA; - } - _sg.gl.cache.cull_mode = SG_CULLMODE_NONE; - _sg.gl.cache.face_winding = SG_FACEWINDING_CW; - _sg.gl.cache.sample_count = 1; - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glPolygonOffset(0.0f, 0.0f); - glDisable(GL_POLYGON_OFFSET_FILL); - glDisable(GL_CULL_FACE); - glFrontFace(GL_CW); - glCullFace(GL_BACK); - glEnable(GL_SCISSOR_TEST); - glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - glEnable(GL_DITHER); - glDisable(GL_POLYGON_OFFSET_FILL); - _sg_stats_add(gl.num_render_state, 10); - #if defined(SOKOL_GLCORE33) - glEnable(GL_MULTISAMPLE); - glEnable(GL_PROGRAM_POINT_SIZE); - _sg_stats_add(gl.num_render_state, 2); - #endif - } + // depth and stencil state + _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.front.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.front.fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.front.depth_fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.front.pass_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.back.fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.depth_fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.pass_op = SG_STENCILOP_KEEP; + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_FALSE); + glDisable(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 0, 0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilMask(0); + _sg_stats_add(gl.num_render_state, 7); + + // blend state + _sg.gl.cache.blend.src_factor_rgb = SG_BLENDFACTOR_ONE; + _sg.gl.cache.blend.dst_factor_rgb = SG_BLENDFACTOR_ZERO; + _sg.gl.cache.blend.op_rgb = SG_BLENDOP_ADD; + _sg.gl.cache.blend.src_factor_alpha = SG_BLENDFACTOR_ONE; + _sg.gl.cache.blend.dst_factor_alpha = SG_BLENDFACTOR_ZERO; + _sg.gl.cache.blend.op_alpha = SG_BLENDOP_ADD; + glDisable(GL_BLEND); + glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); + glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); + glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); + _sg_stats_add(gl.num_render_state, 4); + + // standalone state + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA; + } + _sg.gl.cache.cull_mode = SG_CULLMODE_NONE; + _sg.gl.cache.face_winding = SG_FACEWINDING_CW; + _sg.gl.cache.sample_count = 1; + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glPolygonOffset(0.0f, 0.0f); + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_CULL_FACE); + glFrontFace(GL_CW); + glCullFace(GL_BACK); + glEnable(GL_SCISSOR_TEST); + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); + glEnable(GL_DITHER); + glDisable(GL_POLYGON_OFFSET_FILL); + _sg_stats_add(gl.num_render_state, 10); + #if defined(SOKOL_GLCORE33) + glEnable(GL_MULTISAMPLE); + glEnable(GL_PROGRAM_POINT_SIZE); + _sg_stats_add(gl.num_render_state, 2); + #endif } _SOKOL_PRIVATE void _sg_gl_setup_backend(const sg_desc* desc) { _SOKOL_UNUSED(desc); - SOKOL_ASSERT(desc->context.gl.default_framebuffer_cb == 0 || desc->context.gl.default_framebuffer_userdata_cb == 0); // assumes that _sg.gl is already zero-initialized _sg.gl.valid = true; @@ -7829,33 +7877,9 @@ _SOKOL_PRIVATE void _sg_gl_setup_backend(const sg_desc* desc) { #elif defined(SOKOL_GLES3) _sg_gl_init_caps_gles3(); #endif -} - -_SOKOL_PRIVATE void _sg_gl_discard_backend(void) { - SOKOL_ASSERT(_sg.gl.valid); - _sg.gl.valid = false; - #if defined(_SOKOL_USE_WIN32_GL_LOADER) - _sg_gl_unload_opengl(); - #endif -} -_SOKOL_PRIVATE void _sg_gl_activate_context(_sg_context_t* ctx) { - SOKOL_ASSERT(_sg.gl.valid); - // NOTE: ctx can be 0 to unset the current context - _sg.gl.cur_context = ctx; - _sg_gl_reset_state_cache(); -} - -//-- GL backend resource creation and destruction ------------------------------ -_SOKOL_PRIVATE sg_resource_state _sg_gl_create_context(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - SOKOL_ASSERT(0 == ctx->default_framebuffer); - _SG_GL_CHECK_ERROR(); - glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&ctx->default_framebuffer); - _SG_GL_CHECK_ERROR(); - SOKOL_ASSERT(0 == ctx->vao); - glGenVertexArrays(1, &ctx->vao); - glBindVertexArray(ctx->vao); + glGenVertexArrays(1, &_sg.gl.vao); + glBindVertexArray(_sg.gl.vao); _SG_GL_CHECK_ERROR(); // incoming texture data is generally expected to be packed tightly glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -7863,17 +7887,21 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_context(_sg_context_t* ctx) { // enable seamless cubemap sampling (only desktop GL) glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); #endif - return SG_RESOURCESTATE_VALID; + _sg_gl_reset_state_cache(); } -_SOKOL_PRIVATE void _sg_gl_discard_context(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - if (ctx->vao) { - glDeleteVertexArrays(1, &ctx->vao); +_SOKOL_PRIVATE void _sg_gl_discard_backend(void) { + SOKOL_ASSERT(_sg.gl.valid); + if (_sg.gl.vao) { + glDeleteVertexArrays(1, &_sg.gl.vao); } - _SG_GL_CHECK_ERROR(); + #if defined(_SOKOL_USE_WIN32_GL_LOADER) + _sg_gl_unload_opengl(); + #endif + _sg.gl.valid = false; } +//-- GL backend resource creation and destruction ------------------------------ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { SOKOL_ASSERT(buf && desc); _SG_GL_CHECK_ERROR(); @@ -8303,7 +8331,7 @@ _SOKOL_PRIVATE void _sg_gl_discard_pipeline(_sg_pipeline_t* pip) { _sg_gl_cache_invalidate_pipeline(pip); } -_SOKOL_PRIVATE void _sg_gl_fb_attach_texture(const _sg_gl_attachment_t* gl_att, const _sg_pass_attachment_common_t* cmn_att, GLenum gl_att_type) { +_SOKOL_PRIVATE void _sg_gl_fb_attach_texture(const _sg_gl_attachment_t* gl_att, const _sg_attachment_common_t* cmn_att, GLenum gl_att_type) { const _sg_image_t* img = gl_att->image; SOKOL_ASSERT(img); const GLuint gl_tex = img->gl.tex[0]; @@ -8335,35 +8363,35 @@ _SOKOL_PRIVATE GLenum _sg_gl_depth_stencil_attachment_type(const _sg_gl_attachme } } -_SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_image, const sg_pass_desc* desc) { - SOKOL_ASSERT(pass && desc); +_SOKOL_PRIVATE sg_resource_state _sg_gl_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_image, const sg_attachments_desc* desc) { + SOKOL_ASSERT(atts && desc); SOKOL_ASSERT(color_images && resolve_images); _SG_GL_CHECK_ERROR(); // copy image pointers - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - const sg_pass_attachment_desc* color_desc = &desc->color_attachments[i]; + for (int i = 0; i < atts->cmn.num_colors; i++) { + const sg_attachment_desc* color_desc = &desc->colors[i]; _SOKOL_UNUSED(color_desc); SOKOL_ASSERT(color_desc->image.id != SG_INVALID_ID); - SOKOL_ASSERT(0 == pass->gl.color_atts[i].image); + SOKOL_ASSERT(0 == atts->gl.colors[i].image); SOKOL_ASSERT(color_images[i] && (color_images[i]->slot.id == color_desc->image.id)); SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(color_images[i]->cmn.pixel_format)); - pass->gl.color_atts[i].image = color_images[i]; + atts->gl.colors[i].image = color_images[i]; - const sg_pass_attachment_desc* resolve_desc = &desc->resolve_attachments[i]; + const sg_attachment_desc* resolve_desc = &desc->resolves[i]; if (resolve_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(0 == pass->gl.resolve_atts[i].image); + SOKOL_ASSERT(0 == atts->gl.resolves[i].image); SOKOL_ASSERT(resolve_images[i] && (resolve_images[i]->slot.id == resolve_desc->image.id)); SOKOL_ASSERT(color_images[i] && (color_images[i]->cmn.pixel_format == resolve_images[i]->cmn.pixel_format)); - pass->gl.resolve_atts[i].image = resolve_images[i]; + atts->gl.resolves[i].image = resolve_images[i]; } } - SOKOL_ASSERT(0 == pass->gl.ds_att.image); - const sg_pass_attachment_desc* ds_desc = &desc->depth_stencil_attachment; + SOKOL_ASSERT(0 == atts->gl.depth_stencil.image); + const sg_attachment_desc* ds_desc = &desc->depth_stencil; if (ds_desc->image.id != SG_INVALID_ID) { SOKOL_ASSERT(ds_image && (ds_image->slot.id == ds_desc->image.id)); SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(ds_image->cmn.pixel_format)); - pass->gl.ds_att.image = ds_image; + atts->gl.depth_stencil.image = ds_image; } // store current framebuffer binding (restored at end of function) @@ -8371,31 +8399,31 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_ glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&gl_orig_fb); // create a framebuffer object - glGenFramebuffers(1, &pass->gl.fb); - glBindFramebuffer(GL_FRAMEBUFFER, pass->gl.fb); + glGenFramebuffers(1, &atts->gl.fb); + glBindFramebuffer(GL_FRAMEBUFFER, atts->gl.fb); // attach color attachments to framebuffer - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - const _sg_image_t* color_img = pass->gl.color_atts[i].image; + for (int i = 0; i < atts->cmn.num_colors; i++) { + const _sg_image_t* color_img = atts->gl.colors[i].image; SOKOL_ASSERT(color_img); const GLuint gl_msaa_render_buffer = color_img->gl.msaa_render_buffer; if (gl_msaa_render_buffer) { glFramebufferRenderbuffer(GL_FRAMEBUFFER, (GLenum)(GL_COLOR_ATTACHMENT0+i), GL_RENDERBUFFER, gl_msaa_render_buffer); } else { const GLenum gl_att_type = (GLenum)(GL_COLOR_ATTACHMENT0 + i); - _sg_gl_fb_attach_texture(&pass->gl.color_atts[i], &pass->cmn.color_atts[i], gl_att_type); + _sg_gl_fb_attach_texture(&atts->gl.colors[i], &atts->cmn.colors[i], gl_att_type); } } // attach depth-stencil attachment - if (pass->gl.ds_att.image) { - const GLenum gl_att = _sg_gl_depth_stencil_attachment_type(&pass->gl.ds_att); - const _sg_image_t* ds_img = pass->gl.ds_att.image; + if (atts->gl.depth_stencil.image) { + const GLenum gl_att = _sg_gl_depth_stencil_attachment_type(&atts->gl.depth_stencil); + const _sg_image_t* ds_img = atts->gl.depth_stencil.image; const GLuint gl_msaa_render_buffer = ds_img->gl.msaa_render_buffer; if (gl_msaa_render_buffer) { glFramebufferRenderbuffer(GL_FRAMEBUFFER, gl_att, GL_RENDERBUFFER, gl_msaa_render_buffer); } else { - const GLenum gl_att_type = _sg_gl_depth_stencil_attachment_type(&pass->gl.ds_att); - _sg_gl_fb_attach_texture(&pass->gl.ds_att, &pass->cmn.ds_att, gl_att_type); + const GLenum gl_att_type = _sg_gl_depth_stencil_attachment_type(&atts->gl.depth_stencil); + _sg_gl_fb_attach_texture(&atts->gl.depth_stencil, &atts->cmn.depth_stencil, gl_att_type); } } @@ -8434,16 +8462,16 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_ GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }; - glDrawBuffers(pass->cmn.num_color_atts, gl_draw_bufs); + glDrawBuffers(atts->cmn.num_colors, gl_draw_bufs); // create MSAA resolve framebuffers if necessary - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - _sg_gl_attachment_t* gl_resolve_att = &pass->gl.resolve_atts[i]; + for (int i = 0; i < atts->cmn.num_colors; i++) { + _sg_gl_attachment_t* gl_resolve_att = &atts->gl.resolves[i]; if (gl_resolve_att->image) { - _sg_pass_attachment_t* cmn_resolve_att = &pass->cmn.resolve_atts[i]; - SOKOL_ASSERT(0 == pass->gl.msaa_resolve_framebuffer[i]); - glGenFramebuffers(1, &pass->gl.msaa_resolve_framebuffer[i]); - glBindFramebuffer(GL_FRAMEBUFFER, pass->gl.msaa_resolve_framebuffer[i]); + _sg_attachment_common_t* cmn_resolve_att = &atts->cmn.resolves[i]; + SOKOL_ASSERT(0 == atts->gl.msaa_resolve_framebuffer[i]); + glGenFramebuffers(1, &atts->gl.msaa_resolve_framebuffer[i]); + glBindFramebuffer(GL_FRAMEBUFFER, atts->gl.msaa_resolve_framebuffer[i]); _sg_gl_fb_attach_texture(gl_resolve_att, cmn_resolve_att, GL_COLOR_ATTACHMENT0); // check if framebuffer is complete const GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -8481,51 +8509,43 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_ return SG_RESOURCESTATE_VALID; } -_SOKOL_PRIVATE void _sg_gl_discard_pass(_sg_pass_t* pass) { - SOKOL_ASSERT(pass); - SOKOL_ASSERT(pass != _sg.gl.cur_pass); +_SOKOL_PRIVATE void _sg_gl_discard_attachments(_sg_attachments_t* atts) { + SOKOL_ASSERT(atts); _SG_GL_CHECK_ERROR(); - if (0 != pass->gl.fb) { - glDeleteFramebuffers(1, &pass->gl.fb); + if (0 != atts->gl.fb) { + glDeleteFramebuffers(1, &atts->gl.fb); } for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (pass->gl.msaa_resolve_framebuffer[i]) { - glDeleteFramebuffers(1, &pass->gl.msaa_resolve_framebuffer[i]); + if (atts->gl.msaa_resolve_framebuffer[i]) { + glDeleteFramebuffers(1, &atts->gl.msaa_resolve_framebuffer[i]); } } _SG_GL_CHECK_ERROR(); } -_SOKOL_PRIVATE _sg_image_t* _sg_gl_pass_color_image(const _sg_pass_t* pass, int index) { - SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return pass->gl.color_atts[index].image; +_SOKOL_PRIVATE _sg_image_t* _sg_gl_attachments_color_image(const _sg_attachments_t* atts, int index) { + SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + return atts->gl.colors[index].image; } -_SOKOL_PRIVATE _sg_image_t* _sg_gl_pass_resolve_image(const _sg_pass_t* pass, int index) { - SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return pass->gl.resolve_atts[index].image; +_SOKOL_PRIVATE _sg_image_t* _sg_gl_attachments_resolve_image(const _sg_attachments_t* atts, int index) { + SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + return atts->gl.resolves[index].image; } -_SOKOL_PRIVATE _sg_image_t* _sg_gl_pass_ds_image(const _sg_pass_t* pass) { - SOKOL_ASSERT(pass); - return pass->gl.ds_att.image; +_SOKOL_PRIVATE _sg_image_t* _sg_gl_attachments_ds_image(const _sg_attachments_t* atts) { + SOKOL_ASSERT(atts); + return atts->gl.depth_stencil.image; } -_SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { +_SOKOL_PRIVATE void _sg_gl_begin_pass(const sg_pass* pass) { // FIXME: what if a texture used as render target is still bound, should we // unbind all currently bound textures in begin pass? - SOKOL_ASSERT(action); - SOKOL_ASSERT(!_sg.gl.in_pass); + SOKOL_ASSERT(pass); _SG_GL_CHECK_ERROR(); - _sg.gl.in_pass = true; - _sg.gl.cur_pass = pass; // can be 0 - if (pass) { - _sg.gl.cur_pass_id.id = pass->slot.id; - } else { - _sg.gl.cur_pass_id.id = SG_INVALID_ID; - } - _sg.gl.cur_pass_width = w; - _sg.gl.cur_pass_height = h; + const _sg_attachments_t* atts = _sg.cur_pass.atts; + const sg_swapchain* swapchain = &pass->swapchain; + const sg_pass_action* action = &pass->action; // bind the render pass framebuffer // @@ -8535,32 +8555,28 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac // // This will need a cleaner solution (e.g. allowing to configure // sokol_app.h with an sRGB or RGB framebuffer. - if (pass) { + if (atts) { // offscreen pass - SOKOL_ASSERT(pass->gl.fb); + SOKOL_ASSERT(atts->gl.fb); #if defined(SOKOL_GLCORE33) glEnable(GL_FRAMEBUFFER_SRGB); #endif - glBindFramebuffer(GL_FRAMEBUFFER, pass->gl.fb); + glBindFramebuffer(GL_FRAMEBUFFER, atts->gl.fb); } else { // default pass - SOKOL_ASSERT(_sg.gl.cur_context); #if defined(SOKOL_GLCORE33) glDisable(GL_FRAMEBUFFER_SRGB); #endif - if (_sg.desc.context.gl.default_framebuffer_userdata_cb) { - _sg.gl.cur_context->default_framebuffer = _sg.desc.context.gl.default_framebuffer_userdata_cb(_sg.desc.context.gl.user_data); - } else if (_sg.desc.context.gl.default_framebuffer_cb) { - _sg.gl.cur_context->default_framebuffer = _sg.desc.context.gl.default_framebuffer_cb(); - } - - glBindFramebuffer(GL_FRAMEBUFFER, _sg.gl.cur_context->default_framebuffer); + // NOTE: on some platforms, the default framebuffer of a context + // is null, so we can't actually assert here that the + // framebuffer has been provided + glBindFramebuffer(GL_FRAMEBUFFER, swapchain->gl.framebuffer); } - glViewport(0, 0, w, h); - glScissor(0, 0, w, h); + glViewport(0, 0, _sg.cur_pass.width, _sg.cur_pass.height); + glScissor(0, 0, _sg.cur_pass.width, _sg.cur_pass.height); // number of color attachments - const int num_color_atts = pass ? pass->cmn.num_color_atts : 1; + const int num_color_atts = atts ? atts->cmn.num_colors : 1; // clear color and depth-stencil attachments if needed bool clear_any_color = false; @@ -8618,7 +8634,7 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac glClearBufferfv(GL_COLOR, i, &action->colors[i].clear_value.r); } } - if ((pass == 0) || (pass->gl.ds_att.image)) { + if ((atts == 0) || (atts->gl.depth_stencil.image)) { if (clear_depth && clear_stencil) { glClearBufferfi(GL_DEPTH_STENCIL, 0, action->depth.clear_value, action->stencil.clear_value); } else if (clear_depth) { @@ -8639,26 +8655,25 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac } _SOKOL_PRIVATE void _sg_gl_end_pass(void) { - SOKOL_ASSERT(_sg.gl.in_pass); _SG_GL_CHECK_ERROR(); - if (_sg.gl.cur_pass) { - const _sg_pass_t* pass = _sg.gl.cur_pass; - SOKOL_ASSERT(pass->slot.id == _sg.gl.cur_pass_id.id); + if (_sg.cur_pass.atts) { + const _sg_attachments_t* atts = _sg.cur_pass.atts; + SOKOL_ASSERT(atts->slot.id == _sg.cur_pass.atts_id.id); bool fb_read_bound = false; bool fb_draw_bound = false; - const int num_atts = pass->cmn.num_color_atts; - for (int i = 0; i < num_atts; i++) { + const int num_color_atts = atts->cmn.num_colors; + for (int i = 0; i < num_color_atts; i++) { // perform MSAA resolve if needed - if (pass->gl.msaa_resolve_framebuffer[i] != 0) { + if (atts->gl.msaa_resolve_framebuffer[i] != 0) { if (!fb_read_bound) { - SOKOL_ASSERT(pass->gl.fb); - glBindFramebuffer(GL_READ_FRAMEBUFFER, pass->gl.fb); + SOKOL_ASSERT(atts->gl.fb); + glBindFramebuffer(GL_READ_FRAMEBUFFER, atts->gl.fb); fb_read_bound = true; } - const int w = pass->gl.color_atts[i].image->cmn.width; - const int h = pass->gl.color_atts[i].image->cmn.height; - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, pass->gl.msaa_resolve_framebuffer[i]); + const int w = atts->gl.colors[i].image->cmn.width; + const int h = atts->gl.colors[i].image->cmn.height; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, atts->gl.msaa_resolve_framebuffer[i]); glReadBuffer((GLenum)(GL_COLOR_ATTACHMENT0 + i)); glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); fb_draw_bound = true; @@ -8670,19 +8685,19 @@ _SOKOL_PRIVATE void _sg_gl_end_pass(void) { #if defined(SOKOL_GLES3) // need to restore framebuffer binding before invalidate if the MSAA resolve had changed the binding if (fb_draw_bound) { - glBindFramebuffer(GL_FRAMEBUFFER, pass->gl.fb); + glBindFramebuffer(GL_FRAMEBUFFER, atts->gl.fb); } GLenum invalidate_atts[SG_MAX_COLOR_ATTACHMENTS + 2] = { 0 }; int att_index = 0; - for (int i = 0; i < num_atts; i++) { + for (int i = 0; i < num_color_atts; i++) { if (_sg.gl.color_store_actions[i] == SG_STOREACTION_DONTCARE) { invalidate_atts[att_index++] = (GLenum)(GL_COLOR_ATTACHMENT0 + i); } } - if (_sg.gl.depth_store_action == SG_STOREACTION_DONTCARE) { + if ((_sg.gl.depth_store_action == SG_STOREACTION_DONTCARE) && (_sg.cur_pass.atts->cmn.depth_stencil.image_id.id != SG_INVALID_ID)) { invalidate_atts[att_index++] = GL_DEPTH_ATTACHMENT; } - if (_sg.gl.stencil_store_action == SG_STOREACTION_DONTCARE) { + if ((_sg.gl.stencil_store_action == SG_STOREACTION_DONTCARE) && (_sg.cur_pass.atts->cmn.depth_stencil.image_id.id != SG_INVALID_ID)) { invalidate_atts[att_index++] = GL_STENCIL_ATTACHMENT; } if (att_index > 0) { @@ -8690,27 +8705,16 @@ _SOKOL_PRIVATE void _sg_gl_end_pass(void) { } #endif } - - _sg.gl.cur_pass = 0; - _sg.gl.cur_pass_id.id = SG_INVALID_ID; - _sg.gl.cur_pass_width = 0; - _sg.gl.cur_pass_height = 0; - - SOKOL_ASSERT(_sg.gl.cur_context); - glBindFramebuffer(GL_FRAMEBUFFER, _sg.gl.cur_context->default_framebuffer); - _sg.gl.in_pass = false; _SG_GL_CHECK_ERROR(); } _SOKOL_PRIVATE void _sg_gl_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_sg.gl.in_pass); - y = origin_top_left ? (_sg.gl.cur_pass_height - (y+h)) : y; + y = origin_top_left ? (_sg.cur_pass.height - (y+h)) : y; glViewport(x, y, w, h); } _SOKOL_PRIVATE void _sg_gl_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_sg.gl.in_pass); - y = origin_top_left ? (_sg.gl.cur_pass_height - (y+h)) : y; + y = origin_top_left ? (_sg.cur_pass.height - (y+h)) : y; glScissor(x, y, w, h); } @@ -9109,7 +9113,6 @@ _SOKOL_PRIVATE void _sg_gl_draw(int base_element, int num_elements, int num_inst } _SOKOL_PRIVATE void _sg_gl_commit(void) { - SOKOL_ASSERT(!_sg.gl.in_pass); // "soft" clear bindings (only those that are actually bound) _sg_gl_cache_clear_buffer_bindings(false); _sg_gl_cache_clear_texture_sampler_bindings(false); @@ -9938,18 +9941,11 @@ _SOKOL_PRIVATE void _sg_d3d11_init_caps(void) { _SOKOL_PRIVATE void _sg_d3d11_setup_backend(const sg_desc* desc) { // assume _sg.d3d11 already is zero-initialized SOKOL_ASSERT(desc); - SOKOL_ASSERT(desc->context.d3d11.device); - SOKOL_ASSERT(desc->context.d3d11.device_context); - SOKOL_ASSERT(desc->context.d3d11.render_target_view_cb || desc->context.d3d11.render_target_view_userdata_cb); - SOKOL_ASSERT(desc->context.d3d11.depth_stencil_view_cb || desc->context.d3d11.depth_stencil_view_userdata_cb); + SOKOL_ASSERT(desc->environment.d3d11.device); + SOKOL_ASSERT(desc->environment.d3d11.device_context); _sg.d3d11.valid = true; - _sg.d3d11.dev = (ID3D11Device*) desc->context.d3d11.device; - _sg.d3d11.ctx = (ID3D11DeviceContext*) desc->context.d3d11.device_context; - _sg.d3d11.rtv_cb = desc->context.d3d11.render_target_view_cb; - _sg.d3d11.rtv_userdata_cb = desc->context.d3d11.render_target_view_userdata_cb; - _sg.d3d11.dsv_cb = desc->context.d3d11.depth_stencil_view_cb; - _sg.d3d11.dsv_userdata_cb = desc->context.d3d11.depth_stencil_view_userdata_cb; - _sg.d3d11.user_data = desc->context.d3d11.user_data; + _sg.d3d11.dev = (ID3D11Device*) desc->environment.d3d11.device; + _sg.d3d11.ctx = (ID3D11DeviceContext*) desc->environment.d3d11.device_context; _sg_d3d11_init_caps(); } @@ -9968,23 +9964,6 @@ _SOKOL_PRIVATE void _sg_d3d11_reset_state_cache(void) { _sg_d3d11_clear_state(); } -_SOKOL_PRIVATE void _sg_d3d11_activate_context(_sg_context_t* ctx) { - _SOKOL_UNUSED(ctx); - _sg_d3d11_clear_state(); -} - -_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_context(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - _SOKOL_UNUSED(ctx); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_d3d11_discard_context(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - _SOKOL_UNUSED(ctx); - // empty -} - _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { SOKOL_ASSERT(buf && desc); SOKOL_ASSERT(!buf->d3d11.buf); @@ -10588,42 +10567,42 @@ _SOKOL_PRIVATE void _sg_d3d11_discard_pipeline(_sg_pipeline_t* pip) { } } -_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_pass_desc* desc) { - SOKOL_ASSERT(pass && desc); +_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_attachments_desc* desc) { + SOKOL_ASSERT(atts && desc); SOKOL_ASSERT(color_images && resolve_images); SOKOL_ASSERT(_sg.d3d11.dev); // copy image pointers - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - const sg_pass_attachment_desc* color_desc = &desc->color_attachments[i]; + for (int i = 0; i < atts->cmn.num_colors; i++) { + const sg_attachment_desc* color_desc = &desc->colors[i]; _SOKOL_UNUSED(color_desc); SOKOL_ASSERT(color_desc->image.id != SG_INVALID_ID); - SOKOL_ASSERT(0 == pass->d3d11.color_atts[i].image); + SOKOL_ASSERT(0 == atts->d3d11.colors[i].image); SOKOL_ASSERT(color_images[i] && (color_images[i]->slot.id == color_desc->image.id)); SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(color_images[i]->cmn.pixel_format)); - pass->d3d11.color_atts[i].image = color_images[i]; + atts->d3d11.colors[i].image = color_images[i]; - const sg_pass_attachment_desc* resolve_desc = &desc->resolve_attachments[i]; + const sg_attachment_desc* resolve_desc = &desc->resolves[i]; if (resolve_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(0 == pass->d3d11.resolve_atts[i].image); + SOKOL_ASSERT(0 == atts->d3d11.resolves[i].image); SOKOL_ASSERT(resolve_images[i] && (resolve_images[i]->slot.id == resolve_desc->image.id)); SOKOL_ASSERT(color_images[i] && (color_images[i]->cmn.pixel_format == resolve_images[i]->cmn.pixel_format)); - pass->d3d11.resolve_atts[i].image = resolve_images[i]; + atts->d3d11.resolves[i].image = resolve_images[i]; } } - SOKOL_ASSERT(0 == pass->d3d11.ds_att.image); - const sg_pass_attachment_desc* ds_desc = &desc->depth_stencil_attachment; + SOKOL_ASSERT(0 == atts->d3d11.depth_stencil.image); + const sg_attachment_desc* ds_desc = &desc->depth_stencil; if (ds_desc->image.id != SG_INVALID_ID) { SOKOL_ASSERT(ds_img && (ds_img->slot.id == ds_desc->image.id)); SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(ds_img->cmn.pixel_format)); - pass->d3d11.ds_att.image = ds_img; + atts->d3d11.depth_stencil.image = ds_img; } // create render-target views - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - const _sg_pass_attachment_t* cmn_color_att = &pass->cmn.color_atts[i]; + for (int i = 0; i < atts->cmn.num_colors; i++) { + const _sg_attachment_common_t* cmn_color_att = &atts->cmn.colors[i]; const _sg_image_t* color_img = color_images[i]; - SOKOL_ASSERT(0 == pass->d3d11.color_atts[i].view.rtv); + SOKOL_ASSERT(0 == atts->d3d11.colors[i].view.rtv); const bool msaa = color_img->cmn.sample_count > 1; D3D11_RENDER_TARGET_VIEW_DESC d3d11_rtv_desc; _sg_clear(&d3d11_rtv_desc, sizeof(d3d11_rtv_desc)); @@ -10655,15 +10634,15 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_ima d3d11_rtv_desc.Texture3D.WSize = 1; } SOKOL_ASSERT(color_img->d3d11.res); - HRESULT hr = _sg_d3d11_CreateRenderTargetView(_sg.d3d11.dev, color_img->d3d11.res, &d3d11_rtv_desc, &pass->d3d11.color_atts[i].view.rtv); - if (!(SUCCEEDED(hr) && pass->d3d11.color_atts[i].view.rtv)) { + HRESULT hr = _sg_d3d11_CreateRenderTargetView(_sg.d3d11.dev, color_img->d3d11.res, &d3d11_rtv_desc, &atts->d3d11.colors[i].view.rtv); + if (!(SUCCEEDED(hr) && atts->d3d11.colors[i].view.rtv)) { _SG_ERROR(D3D11_CREATE_RTV_FAILED); return SG_RESOURCESTATE_FAILED; } } - SOKOL_ASSERT(0 == pass->d3d11.ds_att.view.dsv); + SOKOL_ASSERT(0 == atts->d3d11.depth_stencil.view.dsv); if (ds_desc->image.id != SG_INVALID_ID) { - const _sg_pass_attachment_t* cmn_ds_att = &pass->cmn.ds_att; + const _sg_attachment_common_t* cmn_ds_att = &atts->cmn.depth_stencil; const bool msaa = ds_img->cmn.sample_count > 1; D3D11_DEPTH_STENCIL_VIEW_DESC d3d11_dsv_desc; _sg_clear(&d3d11_dsv_desc, sizeof(d3d11_dsv_desc)); @@ -10689,8 +10668,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_ima } } SOKOL_ASSERT(ds_img->d3d11.res); - HRESULT hr = _sg_d3d11_CreateDepthStencilView(_sg.d3d11.dev, ds_img->d3d11.res, &d3d11_dsv_desc, &pass->d3d11.ds_att.view.dsv); - if (!(SUCCEEDED(hr) && pass->d3d11.ds_att.view.dsv)) { + HRESULT hr = _sg_d3d11_CreateDepthStencilView(_sg.d3d11.dev, ds_img->d3d11.res, &d3d11_dsv_desc, &atts->d3d11.depth_stencil.view.dsv); + if (!(SUCCEEDED(hr) && atts->d3d11.depth_stencil.view.dsv)) { _SG_ERROR(D3D11_CREATE_DSV_FAILED); return SG_RESOURCESTATE_FAILED; } @@ -10698,98 +10677,85 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_ima return SG_RESOURCESTATE_VALID; } -_SOKOL_PRIVATE void _sg_d3d11_discard_pass(_sg_pass_t* pass) { - SOKOL_ASSERT(pass); - SOKOL_ASSERT(pass != _sg.d3d11.cur_pass); +_SOKOL_PRIVATE void _sg_d3d11_discard_attachments(_sg_attachments_t* atts) { + SOKOL_ASSERT(atts); for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (pass->d3d11.color_atts[i].view.rtv) { - _sg_d3d11_Release(pass->d3d11.color_atts[i].view.rtv); + if (atts->d3d11.colors[i].view.rtv) { + _sg_d3d11_Release(atts->d3d11.colors[i].view.rtv); } - if (pass->d3d11.resolve_atts[i].view.rtv) { - _sg_d3d11_Release(pass->d3d11.resolve_atts[i].view.rtv); + if (atts->d3d11.resolves[i].view.rtv) { + _sg_d3d11_Release(atts->d3d11.resolves[i].view.rtv); } } - if (pass->d3d11.ds_att.view.dsv) { - _sg_d3d11_Release(pass->d3d11.ds_att.view.dsv); + if (atts->d3d11.depth_stencil.view.dsv) { + _sg_d3d11_Release(atts->d3d11.depth_stencil.view.dsv); } } -_SOKOL_PRIVATE _sg_image_t* _sg_d3d11_pass_color_image(const _sg_pass_t* pass, int index) { - SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return pass->d3d11.color_atts[index].image; +_SOKOL_PRIVATE _sg_image_t* _sg_d3d11_attachments_color_image(const _sg_attachments_t* atts, int index) { + SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + return atts->d3d11.colors[index].image; } -_SOKOL_PRIVATE _sg_image_t* _sg_d3d11_pass_resolve_image(const _sg_pass_t* pass, int index) { - SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return pass->d3d11.resolve_atts[index].image; +_SOKOL_PRIVATE _sg_image_t* _sg_d3d11_attachments_resolve_image(const _sg_attachments_t* atts, int index) { + SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + return atts->d3d11.resolves[index].image; } -_SOKOL_PRIVATE _sg_image_t* _sg_d3d11_pass_ds_image(const _sg_pass_t* pass) { - SOKOL_ASSERT(pass); - return pass->d3d11.ds_att.image; +_SOKOL_PRIVATE _sg_image_t* _sg_d3d11_attachments_ds_image(const _sg_attachments_t* atts) { + SOKOL_ASSERT(atts); + return atts->d3d11.depth_stencil.image; } -_SOKOL_PRIVATE void _sg_d3d11_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { - SOKOL_ASSERT(action); - SOKOL_ASSERT(!_sg.d3d11.in_pass); - SOKOL_ASSERT(_sg.d3d11.rtv_cb || _sg.d3d11.rtv_userdata_cb); - SOKOL_ASSERT(_sg.d3d11.dsv_cb || _sg.d3d11.dsv_userdata_cb); - _sg.d3d11.in_pass = true; - _sg.d3d11.cur_width = w; - _sg.d3d11.cur_height = h; - if (pass) { - _sg.d3d11.cur_pass = pass; - _sg.d3d11.cur_pass_id.id = pass->slot.id; - _sg.d3d11.num_rtvs = 0; +_SOKOL_PRIVATE void _sg_d3d11_begin_pass(const sg_pass* pass) { + SOKOL_ASSERT(pass); + + const _sg_attachments_t* atts = _sg.cur_pass.atts; + const sg_swapchain* swapchain = &pass->swapchain; + const sg_pass_action* action = &pass->action; + + int num_rtvs = 0; + ID3D11RenderTargetView* rtvs[SG_MAX_COLOR_ATTACHMENTS] = { 0 }; + ID3D11DepthStencilView* dsv = 0; + _sg.d3d11.cur_pass.render_view = 0; + _sg.d3d11.cur_pass.resolve_view = 0; + if (atts) { + num_rtvs = atts->cmn.num_colors; for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - _sg.d3d11.cur_rtvs[i] = pass->d3d11.color_atts[i].view.rtv; - if (_sg.d3d11.cur_rtvs[i]) { - _sg.d3d11.num_rtvs++; - } + rtvs[i] = atts->d3d11.colors[i].view.rtv; } - _sg.d3d11.cur_dsv = pass->d3d11.ds_att.view.dsv; + dsv = atts->d3d11.depth_stencil.view.dsv; } else { - // render to default frame buffer - _sg.d3d11.cur_pass = 0; - _sg.d3d11.cur_pass_id.id = SG_INVALID_ID; - _sg.d3d11.num_rtvs = 1; - if (_sg.d3d11.rtv_cb) { - _sg.d3d11.cur_rtvs[0] = (ID3D11RenderTargetView*) _sg.d3d11.rtv_cb(); - } else { - _sg.d3d11.cur_rtvs[0] = (ID3D11RenderTargetView*) _sg.d3d11.rtv_userdata_cb(_sg.d3d11.user_data); - } - for (int i = 1; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - _sg.d3d11.cur_rtvs[i] = 0; - } - if (_sg.d3d11.dsv_cb) { - _sg.d3d11.cur_dsv = (ID3D11DepthStencilView*) _sg.d3d11.dsv_cb(); - } else { - _sg.d3d11.cur_dsv = (ID3D11DepthStencilView*) _sg.d3d11.dsv_userdata_cb(_sg.d3d11.user_data); - } - SOKOL_ASSERT(_sg.d3d11.cur_rtvs[0] && _sg.d3d11.cur_dsv); + // NOTE: depth-stencil-view is optional + SOKOL_ASSERT(swapchain->d3d11.render_view); + num_rtvs = 1; + rtvs[0] = (ID3D11RenderTargetView*) swapchain->d3d11.render_view; + dsv = (ID3D11DepthStencilView*) swapchain->d3d11.depth_stencil_view; + _sg.d3d11.cur_pass.render_view = (ID3D11RenderTargetView*) swapchain->d3d11.render_view; + _sg.d3d11.cur_pass.resolve_view = (ID3D11RenderTargetView*) swapchain->d3d11.resolve_view; } // apply the render-target- and depth-stencil-views - _sg_d3d11_OMSetRenderTargets(_sg.d3d11.ctx, SG_MAX_COLOR_ATTACHMENTS, _sg.d3d11.cur_rtvs, _sg.d3d11.cur_dsv); + _sg_d3d11_OMSetRenderTargets(_sg.d3d11.ctx, SG_MAX_COLOR_ATTACHMENTS, rtvs, dsv); _sg_stats_add(d3d11.pass.num_om_set_render_targets, 1); // set viewport and scissor rect to cover whole screen D3D11_VIEWPORT vp; _sg_clear(&vp, sizeof(vp)); - vp.Width = (FLOAT) w; - vp.Height = (FLOAT) h; + vp.Width = (FLOAT) _sg.cur_pass.width; + vp.Height = (FLOAT) _sg.cur_pass.height; vp.MaxDepth = 1.0f; _sg_d3d11_RSSetViewports(_sg.d3d11.ctx, 1, &vp); D3D11_RECT rect; rect.left = 0; rect.top = 0; - rect.right = w; - rect.bottom = h; + rect.right = _sg.cur_pass.width; + rect.bottom = _sg.cur_pass.height; _sg_d3d11_RSSetScissorRects(_sg.d3d11.ctx, 1, &rect); // perform clear action - for (int i = 0; i < _sg.d3d11.num_rtvs; i++) { + for (int i = 0; i < num_rtvs; i++) { if (action->colors[i].load_action == SG_LOADACTION_CLEAR) { - _sg_d3d11_ClearRenderTargetView(_sg.d3d11.ctx, _sg.d3d11.cur_rtvs[i], &action->colors[i].clear_value.r); + _sg_d3d11_ClearRenderTargetView(_sg.d3d11.ctx, rtvs[i], &action->colors[i].clear_value.r); _sg_stats_add(d3d11.pass.num_clear_render_target_view, 1); } } @@ -10800,8 +10766,8 @@ _SOKOL_PRIVATE void _sg_d3d11_begin_pass(_sg_pass_t* pass, const sg_pass_action* if (action->stencil.load_action == SG_LOADACTION_CLEAR) { ds_flags |= D3D11_CLEAR_STENCIL; } - if ((0 != ds_flags) && _sg.d3d11.cur_dsv) { - _sg_d3d11_ClearDepthStencilView(_sg.d3d11.ctx, _sg.d3d11.cur_dsv, ds_flags, action->depth.clear_value, action->stencil.clear_value); + if ((0 != ds_flags) && dsv) { + _sg_d3d11_ClearDepthStencilView(_sg.d3d11.ctx, dsv, ds_flags, action->depth.clear_value, action->stencil.clear_value); _sg_stats_add(d3d11.pass.num_clear_depth_stencil_view, 1); } } @@ -10812,18 +10778,18 @@ _SOKOL_PRIVATE UINT _sg_d3d11_calcsubresource(UINT mip_slice, UINT array_slice, } _SOKOL_PRIVATE void _sg_d3d11_end_pass(void) { - SOKOL_ASSERT(_sg.d3d11.in_pass && _sg.d3d11.ctx); - _sg.d3d11.in_pass = false; + SOKOL_ASSERT(_sg.d3d11.ctx); // need to resolve MSAA render attachments into texture? - if (_sg.d3d11.cur_pass) { - SOKOL_ASSERT(_sg.d3d11.cur_pass->slot.id == _sg.d3d11.cur_pass_id.id); - for (int i = 0; i < _sg.d3d11.num_rtvs; i++) { - const _sg_image_t* resolve_img = _sg.d3d11.cur_pass->d3d11.resolve_atts[i].image; + if (_sg.cur_pass.atts_id.id != SG_INVALID_ID) { + // ...for offscreen pass... + SOKOL_ASSERT(_sg.cur_pass.atts && _sg.cur_pass.atts->slot.id == _sg.cur_pass.atts_id.id); + for (int i = 0; i < _sg.cur_pass.atts->cmn.num_colors; i++) { + const _sg_image_t* resolve_img = _sg.cur_pass.atts->d3d11.resolves[i].image; if (resolve_img) { - const _sg_image_t* color_img = _sg.d3d11.cur_pass->d3d11.color_atts[i].image; - const _sg_pass_attachment_t* cmn_color_att = &_sg.d3d11.cur_pass->cmn.color_atts[i]; - const _sg_pass_attachment_t* cmn_resolve_att = &_sg.d3d11.cur_pass->cmn.resolve_atts[i]; + const _sg_image_t* color_img = _sg.cur_pass.atts->d3d11.colors[i].image; + const _sg_attachment_common_t* cmn_color_att = &_sg.cur_pass.atts->cmn.colors[i]; + const _sg_attachment_common_t* cmn_resolve_att = &_sg.cur_pass.atts->cmn.resolves[i]; SOKOL_ASSERT(resolve_img->slot.id == cmn_resolve_att->image_id.id); SOKOL_ASSERT(color_img && (color_img->slot.id == cmn_color_att->image_id.id)); SOKOL_ASSERT(color_img->cmn.sample_count > 1); @@ -10845,25 +10811,37 @@ _SOKOL_PRIVATE void _sg_d3d11_end_pass(void) { _sg_stats_add(d3d11.pass.num_resolve_subresource, 1); } } - } - - _sg.d3d11.cur_pass = 0; - _sg.d3d11.cur_pass_id.id = SG_INVALID_ID; + } else { + // ...for swapchain pass... + if (_sg.d3d11.cur_pass.resolve_view) { + SOKOL_ASSERT(_sg.d3d11.cur_pass.render_view); + SOKOL_ASSERT(_sg.cur_pass.swapchain.sample_count > 1); + SOKOL_ASSERT(_sg.cur_pass.swapchain.color_fmt > SG_PIXELFORMAT_NONE); + ID3D11Resource* d3d11_render_res = 0; + ID3D11Resource* d3d11_resolve_res = 0; + _sg_d3d11_GetResource((ID3D11View*)_sg.d3d11.cur_pass.render_view, &d3d11_render_res); + _sg_d3d11_GetResource((ID3D11View*)_sg.d3d11.cur_pass.resolve_view, &d3d11_resolve_res); + SOKOL_ASSERT(d3d11_render_res); + SOKOL_ASSERT(d3d11_resolve_res); + const sg_pixel_format color_fmt = _sg.cur_pass.swapchain.color_fmt; + _sg_d3d11_ResolveSubresource(_sg.d3d11.ctx, d3d11_resolve_res, 0, d3d11_render_res, 0, _sg_d3d11_rtv_pixel_format(color_fmt)); + _sg_d3d11_Release(d3d11_render_res); + _sg_d3d11_Release(d3d11_resolve_res); + _sg_stats_add(d3d11.pass.num_resolve_subresource, 1); + } + } + _sg.d3d11.cur_pass.render_view = 0; + _sg.d3d11.cur_pass.resolve_view = 0; _sg.d3d11.cur_pipeline = 0; _sg.d3d11.cur_pipeline_id.id = SG_INVALID_ID; - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - _sg.d3d11.cur_rtvs[i] = 0; - } - _sg.d3d11.cur_dsv = 0; _sg_d3d11_clear_state(); } _SOKOL_PRIVATE void _sg_d3d11_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { SOKOL_ASSERT(_sg.d3d11.ctx); - SOKOL_ASSERT(_sg.d3d11.in_pass); D3D11_VIEWPORT vp; vp.TopLeftX = (FLOAT) x; - vp.TopLeftY = (FLOAT) (origin_top_left ? y : (_sg.d3d11.cur_height - (y + h))); + vp.TopLeftY = (FLOAT) (origin_top_left ? y : (_sg.cur_pass.height - (y + h))); vp.Width = (FLOAT) w; vp.Height = (FLOAT) h; vp.MinDepth = 0.0f; @@ -10873,12 +10851,11 @@ _SOKOL_PRIVATE void _sg_d3d11_apply_viewport(int x, int y, int w, int h, bool or _SOKOL_PRIVATE void _sg_d3d11_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { SOKOL_ASSERT(_sg.d3d11.ctx); - SOKOL_ASSERT(_sg.d3d11.in_pass); D3D11_RECT rect; rect.left = x; - rect.top = (origin_top_left ? y : (_sg.d3d11.cur_height - (y + h))); + rect.top = (origin_top_left ? y : (_sg.cur_pass.height - (y + h))); rect.right = x + w; - rect.bottom = origin_top_left ? (y + h) : (_sg.d3d11.cur_height - y); + rect.bottom = origin_top_left ? (y + h) : (_sg.cur_pass.height - y); _sg_d3d11_RSSetScissorRects(_sg.d3d11.ctx, 1, &rect); } @@ -10886,7 +10863,6 @@ _SOKOL_PRIVATE void _sg_d3d11_apply_pipeline(_sg_pipeline_t* pip) { SOKOL_ASSERT(pip); SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); SOKOL_ASSERT(_sg.d3d11.ctx); - SOKOL_ASSERT(_sg.d3d11.in_pass); SOKOL_ASSERT(pip->d3d11.rs && pip->d3d11.bs && pip->d3d11.dss && pip->d3d11.il); _sg.d3d11.cur_pipeline = pip; @@ -10918,7 +10894,6 @@ _SOKOL_PRIVATE bool _sg_d3d11_apply_bindings(_sg_bindings_t* bnd) { SOKOL_ASSERT(bnd); SOKOL_ASSERT(bnd->pip); SOKOL_ASSERT(_sg.d3d11.ctx); - SOKOL_ASSERT(_sg.d3d11.in_pass); // gather all the D3D11 resources into arrays ID3D11Buffer* d3d11_ib = bnd->ib ? bnd->ib->d3d11.buf : 0; @@ -10965,7 +10940,7 @@ _SOKOL_PRIVATE bool _sg_d3d11_apply_bindings(_sg_bindings_t* bnd) { } _SOKOL_PRIVATE void _sg_d3d11_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { - SOKOL_ASSERT(_sg.d3d11.ctx && _sg.d3d11.in_pass); + SOKOL_ASSERT(_sg.d3d11.ctx); SOKOL_ASSERT(_sg.d3d11.cur_pipeline && _sg.d3d11.cur_pipeline->slot.id == _sg.d3d11.cur_pipeline_id.id); SOKOL_ASSERT(_sg.d3d11.cur_pipeline->shader && _sg.d3d11.cur_pipeline->shader->slot.id == _sg.d3d11.cur_pipeline->cmn.shader_id.id); SOKOL_ASSERT(ub_index < _sg.d3d11.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks); @@ -10977,7 +10952,6 @@ _SOKOL_PRIVATE void _sg_d3d11_apply_uniforms(sg_shader_stage stage_index, int ub } _SOKOL_PRIVATE void _sg_d3d11_draw(int base_element, int num_elements, int num_instances) { - SOKOL_ASSERT(_sg.d3d11.in_pass); if (_sg.d3d11.use_indexed_draw) { if (_sg.d3d11.use_instanced_draw) { _sg_d3d11_DrawIndexedInstanced(_sg.d3d11.ctx, (UINT)num_elements, (UINT)num_instances, (UINT)base_element, 0, 0); @@ -10998,7 +10972,7 @@ _SOKOL_PRIVATE void _sg_d3d11_draw(int base_element, int num_elements, int num_i } _SOKOL_PRIVATE void _sg_d3d11_commit(void) { - SOKOL_ASSERT(!_sg.d3d11.in_pass); + // empty } _SOKOL_PRIVATE void _sg_d3d11_update_buffer(_sg_buffer_t* buf, const sg_range* data) { @@ -11469,7 +11443,7 @@ _SOKOL_PRIVATE void _sg_mtl_init_pool(const sg_desc* desc) { 1 * desc->sampler_pool_size + 4 * desc->shader_pool_size + 2 * desc->pipeline_pool_size + - desc->pass_pool_size + + desc->attachments_pool_size + 128 ); _sg.mtl.idpool.pool = [NSMutableArray arrayWithCapacity:(NSUInteger)_sg.mtl.idpool.num_slots]; @@ -11750,21 +11724,14 @@ _SOKOL_PRIVATE void _sg_mtl_init_caps(void) { _SOKOL_PRIVATE void _sg_mtl_setup_backend(const sg_desc* desc) { // assume already zero-initialized SOKOL_ASSERT(desc); - SOKOL_ASSERT(desc->context.metal.device); - SOKOL_ASSERT(desc->context.metal.renderpass_descriptor_cb || desc->context.metal.renderpass_descriptor_userdata_cb); - SOKOL_ASSERT(desc->context.metal.drawable_cb || desc->context.metal.drawable_userdata_cb); + SOKOL_ASSERT(desc->environment.metal.device); SOKOL_ASSERT(desc->uniform_buffer_size > 0); _sg_mtl_init_pool(desc); _sg_mtl_clear_state_cache(); _sg.mtl.valid = true; - _sg.mtl.renderpass_descriptor_cb = desc->context.metal.renderpass_descriptor_cb; - _sg.mtl.renderpass_descriptor_userdata_cb = desc->context.metal.renderpass_descriptor_userdata_cb; - _sg.mtl.drawable_cb = desc->context.metal.drawable_cb; - _sg.mtl.drawable_userdata_cb = desc->context.metal.drawable_userdata_cb; - _sg.mtl.user_data = desc->context.metal.user_data; _sg.mtl.ub_size = desc->uniform_buffer_size; _sg.mtl.sem = dispatch_semaphore_create(SG_NUM_INFLIGHT_FRAMES); - _sg.mtl.device = (__bridge id) desc->context.metal.device; + _sg.mtl.device = (__bridge id) desc->environment.metal.device; _sg.mtl.cmd_queue = [_sg.mtl.device newCommandQueue]; for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { @@ -11845,23 +11812,6 @@ _SOKOL_PRIVATE void _sg_mtl_reset_state_cache(void) { } } -_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_context(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - _SOKOL_UNUSED(ctx); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_mtl_discard_context(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - _SOKOL_UNUSED(ctx); - // empty -} - -_SOKOL_PRIVATE void _sg_mtl_activate_context(_sg_context_t* ctx) { - _SOKOL_UNUSED(ctx); - _sg_mtl_clear_state_cache(); -} - _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { SOKOL_ASSERT(buf && desc); const bool injected = (0 != desc->mtl_buffers[0]); @@ -12353,72 +12303,72 @@ _SOKOL_PRIVATE void _sg_mtl_discard_pipeline(_sg_pipeline_t* pip) { _sg_mtl_release_resource(_sg.frame_index, pip->mtl.dss); } -_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pass(_sg_pass_t* pass, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_pass_desc* desc) { - SOKOL_ASSERT(pass && desc); +_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_attachments_desc* desc) { + SOKOL_ASSERT(atts && desc); SOKOL_ASSERT(color_images && resolve_images); // copy image pointers - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - const sg_pass_attachment_desc* color_desc = &desc->color_attachments[i]; + for (int i = 0; i < atts->cmn.num_colors; i++) { + const sg_attachment_desc* color_desc = &desc->colors[i]; _SOKOL_UNUSED(color_desc); SOKOL_ASSERT(color_desc->image.id != SG_INVALID_ID); - SOKOL_ASSERT(0 == pass->mtl.color_atts[i].image); + SOKOL_ASSERT(0 == atts->mtl.colors[i].image); SOKOL_ASSERT(color_images[i] && (color_images[i]->slot.id == color_desc->image.id)); SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(color_images[i]->cmn.pixel_format)); - pass->mtl.color_atts[i].image = color_images[i]; + atts->mtl.colors[i].image = color_images[i]; - const sg_pass_attachment_desc* resolve_desc = &desc->resolve_attachments[i]; + const sg_attachment_desc* resolve_desc = &desc->resolves[i]; if (resolve_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(0 == pass->mtl.resolve_atts[i].image); + SOKOL_ASSERT(0 == atts->mtl.resolves[i].image); SOKOL_ASSERT(resolve_images[i] && (resolve_images[i]->slot.id == resolve_desc->image.id)); SOKOL_ASSERT(color_images[i] && (color_images[i]->cmn.pixel_format == resolve_images[i]->cmn.pixel_format)); - pass->mtl.resolve_atts[i].image = resolve_images[i]; + atts->mtl.resolves[i].image = resolve_images[i]; } } - SOKOL_ASSERT(0 == pass->mtl.ds_att.image); - const sg_pass_attachment_desc* ds_desc = &desc->depth_stencil_attachment; + SOKOL_ASSERT(0 == atts->mtl.depth_stencil.image); + const sg_attachment_desc* ds_desc = &desc->depth_stencil; if (ds_desc->image.id != SG_INVALID_ID) { SOKOL_ASSERT(ds_img && (ds_img->slot.id == ds_desc->image.id)); SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(ds_img->cmn.pixel_format)); - pass->mtl.ds_att.image = ds_img; + atts->mtl.depth_stencil.image = ds_img; } return SG_RESOURCESTATE_VALID; } -_SOKOL_PRIVATE void _sg_mtl_discard_pass(_sg_pass_t* pass) { - SOKOL_ASSERT(pass); - _SOKOL_UNUSED(pass); +_SOKOL_PRIVATE void _sg_mtl_discard_attachments(_sg_attachments_t* atts) { + SOKOL_ASSERT(atts); + _SOKOL_UNUSED(atts); } -_SOKOL_PRIVATE _sg_image_t* _sg_mtl_pass_color_image(const _sg_pass_t* pass, int index) { +_SOKOL_PRIVATE _sg_image_t* _sg_mtl_attachments_color_image(const _sg_attachments_t* atts, int index) { // NOTE: may return null - SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return pass->mtl.color_atts[index].image; + SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + return atts->mtl.colors[index].image; } -_SOKOL_PRIVATE _sg_image_t* _sg_mtl_pass_resolve_image(const _sg_pass_t* pass, int index) { +_SOKOL_PRIVATE _sg_image_t* _sg_mtl_attachments_resolve_image(const _sg_attachments_t* atts, int index) { // NOTE: may return null - SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); - return pass->mtl.resolve_atts[index].image; + SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + return atts->mtl.resolves[index].image; } -_SOKOL_PRIVATE _sg_image_t* _sg_mtl_pass_ds_image(const _sg_pass_t* pass) { +_SOKOL_PRIVATE _sg_image_t* _sg_mtl_attachments_ds_image(const _sg_attachments_t* atts) { // NOTE: may return null - SOKOL_ASSERT(pass); - return pass->mtl.ds_att.image; + SOKOL_ASSERT(atts); + return atts->mtl.depth_stencil.image; } -_SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { - SOKOL_ASSERT(action); - SOKOL_ASSERT(!_sg.mtl.in_pass); +_SOKOL_PRIVATE void _sg_mtl_begin_pass(const sg_pass* pass) { + SOKOL_ASSERT(pass); SOKOL_ASSERT(_sg.mtl.cmd_queue); SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); - SOKOL_ASSERT(_sg.mtl.renderpass_descriptor_cb || _sg.mtl.renderpass_descriptor_userdata_cb); - _sg.mtl.in_pass = true; - _sg.mtl.cur_width = w; - _sg.mtl.cur_height = h; + SOKOL_ASSERT(nil == _sg.mtl.cur_drawable); _sg_mtl_clear_state_cache(); + const _sg_attachments_t* atts = _sg.cur_pass.atts; + const sg_swapchain* swapchain = &pass->swapchain; + const sg_pass_action* action = &pass->action; + /* if this is the first pass in the frame, create command buffers @@ -12433,7 +12383,11 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* a if (nil == _sg.mtl.cmd_buffer) { // block until the oldest frame in flight has finished dispatch_semaphore_wait(_sg.mtl.sem, DISPATCH_TIME_FOREVER); - _sg.mtl.cmd_buffer = [_sg.mtl.cmd_queue commandBufferWithUnretainedReferences]; + if (_sg.desc.mtl_use_command_buffer_with_retained_references) { + _sg.mtl.cmd_buffer = [_sg.mtl.cmd_queue commandBuffer]; + } else { + _sg.mtl.cmd_buffer = [_sg.mtl.cmd_queue commandBufferWithUnretainedReferences]; + } [_sg.mtl.cmd_buffer enqueue]; [_sg.mtl.cmd_buffer addCompletedHandler:^(id cmd_buf) { // NOTE: this code is called on a different thread! @@ -12447,39 +12401,17 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* a _sg.mtl.cur_ub_base_ptr = (uint8_t*)[_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] contents]; } - // initialize a render pass descriptor - MTLRenderPassDescriptor* pass_desc = nil; - if (pass) { - // offscreen render pass - pass_desc = [MTLRenderPassDescriptor renderPassDescriptor]; - } else { - // default render pass, call user-provided callback to provide render pass descriptor - if (_sg.mtl.renderpass_descriptor_cb) { - pass_desc = (__bridge MTLRenderPassDescriptor*) _sg.mtl.renderpass_descriptor_cb(); - } else { - pass_desc = (__bridge MTLRenderPassDescriptor*) _sg.mtl.renderpass_descriptor_userdata_cb(_sg.mtl.user_data); - } - // pin the swapchain resources into memory so that they outlive their command buffer - // (this is necessary because the command buffer doesn't retain references) - int default_pass_desc_ref = _sg_mtl_add_resource(pass_desc); - _sg_mtl_release_resource(_sg.frame_index, default_pass_desc_ref); - } - if (pass_desc) { - _sg.mtl.pass_valid = true; - } else { - // default pass descriptor will not be valid if window is minimized, don't do any rendering in this case - _sg.mtl.pass_valid = false; - return; - } - if (pass) { + MTLRenderPassDescriptor* pass_desc = [MTLRenderPassDescriptor renderPassDescriptor]; + SOKOL_ASSERT(pass_desc); + if (atts) { // setup pass descriptor for offscreen rendering - SOKOL_ASSERT(pass->slot.state == SG_RESOURCESTATE_VALID); - for (NSUInteger i = 0; i < (NSUInteger)pass->cmn.num_color_atts; i++) { - const _sg_pass_attachment_t* cmn_color_att = &pass->cmn.color_atts[i]; - const _sg_mtl_attachment_t* mtl_color_att = &pass->mtl.color_atts[i]; + SOKOL_ASSERT(atts->slot.state == SG_RESOURCESTATE_VALID); + for (NSUInteger i = 0; i < (NSUInteger)atts->cmn.num_colors; i++) { + const _sg_attachment_common_t* cmn_color_att = &atts->cmn.colors[i]; + const _sg_mtl_attachment_t* mtl_color_att = &atts->mtl.colors[i]; const _sg_image_t* color_att_img = mtl_color_att->image; - const _sg_pass_attachment_t* cmn_resolve_att = &pass->cmn.resolve_atts[i]; - const _sg_mtl_attachment_t* mtl_resolve_att = &pass->mtl.resolve_atts[i]; + const _sg_attachment_common_t* cmn_resolve_att = &atts->cmn.resolves[i]; + const _sg_mtl_attachment_t* mtl_resolve_att = &atts->mtl.resolves[i]; const _sg_image_t* resolve_att_img = mtl_resolve_att->image; SOKOL_ASSERT(color_att_img->slot.state == SG_RESOURCESTATE_VALID); SOKOL_ASSERT(color_att_img->slot.id == cmn_color_att->image_id.id); @@ -12518,16 +12450,16 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* a } } } - const _sg_image_t* ds_att_img = pass->mtl.ds_att.image; + const _sg_image_t* ds_att_img = atts->mtl.depth_stencil.image; if (0 != ds_att_img) { SOKOL_ASSERT(ds_att_img->slot.state == SG_RESOURCESTATE_VALID); - SOKOL_ASSERT(ds_att_img->slot.id == pass->cmn.ds_att.image_id.id); + SOKOL_ASSERT(ds_att_img->slot.id == atts->cmn.depth_stencil.image_id.id); SOKOL_ASSERT(ds_att_img->mtl.tex[ds_att_img->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); pass_desc.depthAttachment.texture = _sg_mtl_id(ds_att_img->mtl.tex[ds_att_img->cmn.active_slot]); pass_desc.depthAttachment.loadAction = _sg_mtl_load_action(action->depth.load_action); pass_desc.depthAttachment.storeAction = _sg_mtl_store_action(action->depth.store_action, false); pass_desc.depthAttachment.clearDepth = action->depth.clear_value; - const _sg_pass_attachment_t* cmn_ds_att = &pass->cmn.ds_att; + const _sg_attachment_common_t* cmn_ds_att = &atts->cmn.depth_stencil; switch (ds_att_img->cmn.type) { case SG_IMAGETYPE_CUBE: case SG_IMAGETYPE_ARRAY: @@ -12556,55 +12488,91 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* a } } } else { - // setup pass descriptor for default rendering + // setup pass descriptor for swapchain rendering + // + // NOTE: at least in macOS Sonoma this no longer seems to be the case, the + // current drawable is also valid in a minimized window + // === + // an MTKView current_drawable will not be valid if window is minimized, don't do any rendering in this case + if (0 == swapchain->metal.current_drawable) { + _sg.cur_pass.valid = false; + return; + } + // pin the swapchain resources into memory so that they outlive their command buffer + // (this is necessary because the command buffer doesn't retain references) + int pass_desc_ref = _sg_mtl_add_resource(pass_desc); + _sg_mtl_release_resource(_sg.frame_index, pass_desc_ref); + + _sg.mtl.cur_drawable = (__bridge id) swapchain->metal.current_drawable; + if (swapchain->sample_count > 1) { + // multi-sampling: render into msaa texture, resolve into drawable texture + id msaa_tex = (__bridge id) swapchain->metal.msaa_color_texture; + SOKOL_ASSERT(msaa_tex != nil); + pass_desc.colorAttachments[0].texture = msaa_tex; + pass_desc.colorAttachments[0].resolveTexture = _sg.mtl.cur_drawable.texture; + pass_desc.colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve; + } else { + // non-msaa: render into current_drawable + pass_desc.colorAttachments[0].texture = _sg.mtl.cur_drawable.texture; + pass_desc.colorAttachments[0].storeAction = MTLStoreActionStore; + } pass_desc.colorAttachments[0].loadAction = _sg_mtl_load_action(action->colors[0].load_action); - sg_color c = action->colors[0].clear_value; + const sg_color c = action->colors[0].clear_value; pass_desc.colorAttachments[0].clearColor = MTLClearColorMake(c.r, c.g, c.b, c.a); - pass_desc.depthAttachment.loadAction = _sg_mtl_load_action(action->depth.load_action); - pass_desc.depthAttachment.clearDepth = action->depth.clear_value; - pass_desc.stencilAttachment.loadAction = _sg_mtl_load_action(action->stencil.load_action); - pass_desc.stencilAttachment.clearStencil = action->stencil.clear_value; + + // optional depth-stencil texture + if (swapchain->metal.depth_stencil_texture) { + id ds_tex = (__bridge id) swapchain->metal.depth_stencil_texture; + SOKOL_ASSERT(ds_tex != nil); + pass_desc.depthAttachment.texture = ds_tex; + pass_desc.depthAttachment.storeAction = MTLStoreActionDontCare; + pass_desc.stencilAttachment.texture = ds_tex; + pass_desc.stencilAttachment.storeAction = MTLStoreActionDontCare; + pass_desc.depthAttachment.loadAction = _sg_mtl_load_action(action->depth.load_action); + pass_desc.depthAttachment.clearDepth = action->depth.clear_value; + pass_desc.stencilAttachment.loadAction = _sg_mtl_load_action(action->stencil.load_action); + pass_desc.stencilAttachment.clearStencil = action->stencil.clear_value; + } } + // NOTE: at least in macOS Sonoma, the following is no longer the case, a valid + // render command encoder is also returned in a minimized window + // === // create a render command encoder, this might return nil if window is minimized _sg.mtl.cmd_encoder = [_sg.mtl.cmd_buffer renderCommandEncoderWithDescriptor:pass_desc]; if (nil == _sg.mtl.cmd_encoder) { - _sg.mtl.pass_valid = false; + _sg.cur_pass.valid = false; return; } + #if defined(SOKOL_DEBUG) + if (pass->label) { + _sg.mtl.cmd_encoder.label = [NSString stringWithUTF8String:pass->label]; + } + #endif + // bind the global uniform buffer, this only happens once per pass _sg_mtl_bind_uniform_buffers(); } _SOKOL_PRIVATE void _sg_mtl_end_pass(void) { - SOKOL_ASSERT(_sg.mtl.in_pass); - _sg.mtl.in_pass = false; - _sg.mtl.pass_valid = false; if (nil != _sg.mtl.cmd_encoder) { [_sg.mtl.cmd_encoder endEncoding]; // NOTE: MTLRenderCommandEncoder is autoreleased _sg.mtl.cmd_encoder = nil; } + // if this is a swapchain pass, present the drawable + if (nil != _sg.mtl.cur_drawable) { + [_sg.mtl.cmd_buffer presentDrawable:_sg.mtl.cur_drawable]; + _sg.mtl.cur_drawable = nil; + } } _SOKOL_PRIVATE void _sg_mtl_commit(void) { - SOKOL_ASSERT(!_sg.mtl.in_pass); - SOKOL_ASSERT(!_sg.mtl.pass_valid); - SOKOL_ASSERT(_sg.mtl.drawable_cb || _sg.mtl.drawable_userdata_cb); SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); SOKOL_ASSERT(nil != _sg.mtl.cmd_buffer); - // present, commit and signal semaphore when done - id cur_drawable = nil; - if (_sg.mtl.drawable_cb) { - cur_drawable = (__bridge id) _sg.mtl.drawable_cb(); - } else { - cur_drawable = (__bridge id) _sg.mtl.drawable_userdata_cb(_sg.mtl.user_data); - } - if (nil != cur_drawable) { - [_sg.mtl.cmd_buffer presentDrawable:cur_drawable]; - } + // commit the frame's command buffer [_sg.mtl.cmd_buffer commit]; // garbage-collect resources pending for release @@ -12621,14 +12589,11 @@ _SOKOL_PRIVATE void _sg_mtl_commit(void) { } _SOKOL_PRIVATE void _sg_mtl_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_sg.mtl.in_pass); - if (!_sg.mtl.pass_valid) { - return; - } SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); + SOKOL_ASSERT(_sg.cur_pass.height > 0); MTLViewport vp; vp.originX = (double) x; - vp.originY = (double) (origin_top_left ? y : (_sg.mtl.cur_height - (y + h))); + vp.originY = (double) (origin_top_left ? y : (_sg.cur_pass.height - (y + h))); vp.width = (double) w; vp.height = (double) h; vp.znear = 0.0; @@ -12637,16 +12602,14 @@ _SOKOL_PRIVATE void _sg_mtl_apply_viewport(int x, int y, int w, int h, bool orig } _SOKOL_PRIVATE void _sg_mtl_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_sg.mtl.in_pass); - if (!_sg.mtl.pass_valid) { - return; - } SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); + SOKOL_ASSERT(_sg.cur_pass.width > 0); + SOKOL_ASSERT(_sg.cur_pass.height > 0); // clip against framebuffer rect - const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.mtl.cur_width, _sg.mtl.cur_height); + const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.cur_pass.width, _sg.cur_pass.height); MTLScissorRect r; r.x = (NSUInteger)clip.x; - r.y = (NSUInteger) (origin_top_left ? clip.y : (_sg.mtl.cur_height - (clip.y + clip.h))); + r.y = (NSUInteger) (origin_top_left ? clip.y : (_sg.cur_pass.height - (clip.y + clip.h))); r.width = (NSUInteger)clip.w; r.height = (NSUInteger)clip.h; [_sg.mtl.cmd_encoder setScissorRect:r]; @@ -12655,10 +12618,6 @@ _SOKOL_PRIVATE void _sg_mtl_apply_scissor_rect(int x, int y, int w, int h, bool _SOKOL_PRIVATE void _sg_mtl_apply_pipeline(_sg_pipeline_t* pip) { SOKOL_ASSERT(pip); SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); - SOKOL_ASSERT(_sg.mtl.in_pass); - if (!_sg.mtl.pass_valid) { - return; - } SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); if (_sg.mtl.state_cache.cur_pipeline_id.id != pip->slot.id) { @@ -12687,10 +12646,6 @@ _SOKOL_PRIVATE void _sg_mtl_apply_pipeline(_sg_pipeline_t* pip) { _SOKOL_PRIVATE bool _sg_mtl_apply_bindings(_sg_bindings_t* bnd) { SOKOL_ASSERT(bnd); SOKOL_ASSERT(bnd->pip); - SOKOL_ASSERT(_sg.mtl.in_pass); - if (!_sg.mtl.pass_valid) { - return false; - } SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); // store index buffer binding, this will be needed later in sg_draw() @@ -12773,10 +12728,6 @@ _SOKOL_PRIVATE bool _sg_mtl_apply_bindings(_sg_bindings_t* bnd) { } _SOKOL_PRIVATE void _sg_mtl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { - SOKOL_ASSERT(_sg.mtl.in_pass); - if (!_sg.mtl.pass_valid) { - return; - } SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); SOKOL_ASSERT(((size_t)_sg.mtl.cur_ub_offset + data->size) <= (size_t)_sg.mtl.ub_size); SOKOL_ASSERT((_sg.mtl.cur_ub_offset & (_SG_MTL_UB_ALIGN-1)) == 0); @@ -12800,10 +12751,6 @@ _SOKOL_PRIVATE void _sg_mtl_apply_uniforms(sg_shader_stage stage_index, int ub_i } _SOKOL_PRIVATE void _sg_mtl_draw(int base_element, int num_elements, int num_instances) { - SOKOL_ASSERT(_sg.mtl.in_pass); - if (!_sg.mtl.pass_valid) { - return; - } SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline && (_sg.mtl.state_cache.cur_pipeline->slot.id == _sg.mtl.state_cache.cur_pipeline_id.id)); if (SG_INDEXTYPE_NONE != _sg.mtl.state_cache.cur_pipeline->cmn.index_type) { @@ -13911,21 +13858,11 @@ _SOKOL_PRIVATE bool _sg_wgpu_apply_vertex_buffers(_sg_bindings_t* bnd) { _SOKOL_PRIVATE void _sg_wgpu_setup_backend(const sg_desc* desc) { SOKOL_ASSERT(desc); - SOKOL_ASSERT(desc->context.wgpu.device); - SOKOL_ASSERT(desc->context.wgpu.render_view_cb || desc->context.wgpu.render_view_userdata_cb); - SOKOL_ASSERT(desc->context.wgpu.resolve_view_cb || desc->context.wgpu.resolve_view_userdata_cb); - SOKOL_ASSERT(desc->context.wgpu.depth_stencil_view_cb || desc->context.wgpu.depth_stencil_view_userdata_cb); + SOKOL_ASSERT(desc->environment.wgpu.device); SOKOL_ASSERT(desc->uniform_buffer_size > 0); _sg.backend = SG_BACKEND_WGPU; _sg.wgpu.valid = true; - _sg.wgpu.dev = (WGPUDevice) desc->context.wgpu.device; - _sg.wgpu.render_view_cb = (WGPUTextureView(*)(void)) desc->context.wgpu.render_view_cb; - _sg.wgpu.render_view_userdata_cb = (WGPUTextureView(*)(void*)) desc->context.wgpu.render_view_userdata_cb; - _sg.wgpu.resolve_view_cb = (WGPUTextureView(*)(void)) desc->context.wgpu.resolve_view_cb; - _sg.wgpu.resolve_view_userdata_cb = (WGPUTextureView(*)(void*)) desc->context.wgpu.resolve_view_userdata_cb; - _sg.wgpu.depth_stencil_view_cb = (WGPUTextureView(*)(void)) desc->context.wgpu.depth_stencil_view_cb; - _sg.wgpu.depth_stencil_view_userdata_cb = (WGPUTextureView(*)(void*)) desc->context.wgpu.depth_stencil_view_userdata_cb; - _sg.wgpu.user_data = desc->context.wgpu.user_data; + _sg.wgpu.dev = (WGPUDevice) desc->environment.wgpu.device; _sg.wgpu.queue = wgpuDeviceGetQueue(_sg.wgpu.dev); SOKOL_ASSERT(_sg.wgpu.queue); @@ -13972,22 +13909,6 @@ _SOKOL_PRIVATE void _sg_wgpu_reset_state_cache(void) { _sg_wgpu_bindings_cache_clear(); } -_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_context(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - _SOKOL_UNUSED(ctx); - return SG_RESOURCESTATE_VALID; -} - -_SOKOL_PRIVATE void _sg_wgpu_discard_context(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - _SOKOL_UNUSED(ctx); -} - -_SOKOL_PRIVATE void _sg_wgpu_activate_context(_sg_context_t* ctx) { - (void)ctx; - // FIXME -} - _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { SOKOL_ASSERT(buf && desc); const bool injected = (0 != desc->wgpu_buffer); @@ -14446,20 +14367,20 @@ _SOKOL_PRIVATE void _sg_wgpu_discard_pipeline(_sg_pipeline_t* pip) { } } -_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pass(_sg_pass_t* pass, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_pass_desc* desc) { - SOKOL_ASSERT(pass && desc); +_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_img, const sg_attachments_desc* desc) { + SOKOL_ASSERT(atts && desc); SOKOL_ASSERT(color_images && resolve_images); // copy image pointers and create renderable wgpu texture views - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - const sg_pass_attachment_desc* color_desc = &desc->color_attachments[i]; + for (int i = 0; i < atts->cmn.num_colors; i++) { + const sg_attachment_desc* color_desc = &desc->colors[i]; _SOKOL_UNUSED(color_desc); SOKOL_ASSERT(color_desc->image.id != SG_INVALID_ID); - SOKOL_ASSERT(0 == pass->wgpu.color_atts[i].image); + SOKOL_ASSERT(0 == atts->wgpu.colors[i].image); SOKOL_ASSERT(color_images[i] && (color_images[i]->slot.id == color_desc->image.id)); SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(color_images[i]->cmn.pixel_format)); SOKOL_ASSERT(color_images[i]->wgpu.tex); - pass->wgpu.color_atts[i].image = color_images[i]; + atts->wgpu.colors[i].image = color_images[i]; WGPUTextureViewDescriptor wgpu_color_view_desc; _sg_clear(&wgpu_color_view_desc, sizeof(wgpu_color_view_desc)); @@ -14467,19 +14388,19 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pass(_sg_pass_t* pass, _sg_imag wgpu_color_view_desc.mipLevelCount = 1; wgpu_color_view_desc.baseArrayLayer = (uint32_t) color_desc->slice; wgpu_color_view_desc.arrayLayerCount = 1; - pass->wgpu.color_atts[i].view = wgpuTextureCreateView(color_images[i]->wgpu.tex, &wgpu_color_view_desc); - if (0 == pass->wgpu.color_atts[i].view) { - _SG_ERROR(WGPU_PASS_CREATE_TEXTURE_VIEW_FAILED); + atts->wgpu.colors[i].view = wgpuTextureCreateView(color_images[i]->wgpu.tex, &wgpu_color_view_desc); + if (0 == atts->wgpu.colors[i].view) { + _SG_ERROR(WGPU_ATTACHMENTS_CREATE_TEXTURE_VIEW_FAILED); return SG_RESOURCESTATE_FAILED; } - const sg_pass_attachment_desc* resolve_desc = &desc->resolve_attachments[i]; + const sg_attachment_desc* resolve_desc = &desc->resolves[i]; if (resolve_desc->image.id != SG_INVALID_ID) { - SOKOL_ASSERT(0 == pass->wgpu.resolve_atts[i].image); + SOKOL_ASSERT(0 == atts->wgpu.resolves[i].image); SOKOL_ASSERT(resolve_images[i] && (resolve_images[i]->slot.id == resolve_desc->image.id)); SOKOL_ASSERT(color_images[i] && (color_images[i]->cmn.pixel_format == resolve_images[i]->cmn.pixel_format)); SOKOL_ASSERT(resolve_images[i]->wgpu.tex); - pass->wgpu.resolve_atts[i].image = resolve_images[i]; + atts->wgpu.resolves[i].image = resolve_images[i]; WGPUTextureViewDescriptor wgpu_resolve_view_desc; _sg_clear(&wgpu_resolve_view_desc, sizeof(wgpu_resolve_view_desc)); @@ -14487,20 +14408,20 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pass(_sg_pass_t* pass, _sg_imag wgpu_resolve_view_desc.mipLevelCount = 1; wgpu_resolve_view_desc.baseArrayLayer = (uint32_t) resolve_desc->slice; wgpu_resolve_view_desc.arrayLayerCount = 1; - pass->wgpu.resolve_atts[i].view = wgpuTextureCreateView(resolve_images[i]->wgpu.tex, &wgpu_resolve_view_desc); - if (0 == pass->wgpu.resolve_atts[i].view) { - _SG_ERROR(WGPU_PASS_CREATE_TEXTURE_VIEW_FAILED); + atts->wgpu.resolves[i].view = wgpuTextureCreateView(resolve_images[i]->wgpu.tex, &wgpu_resolve_view_desc); + if (0 == atts->wgpu.resolves[i].view) { + _SG_ERROR(WGPU_ATTACHMENTS_CREATE_TEXTURE_VIEW_FAILED); return SG_RESOURCESTATE_FAILED; } } } - SOKOL_ASSERT(0 == pass->wgpu.ds_att.image); - const sg_pass_attachment_desc* ds_desc = &desc->depth_stencil_attachment; + SOKOL_ASSERT(0 == atts->wgpu.depth_stencil.image); + const sg_attachment_desc* ds_desc = &desc->depth_stencil; if (ds_desc->image.id != SG_INVALID_ID) { SOKOL_ASSERT(ds_img && (ds_img->slot.id == ds_desc->image.id)); SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(ds_img->cmn.pixel_format)); SOKOL_ASSERT(ds_img->wgpu.tex); - pass->wgpu.ds_att.image = ds_img; + atts->wgpu.depth_stencil.image = ds_img; WGPUTextureViewDescriptor wgpu_ds_view_desc; _sg_clear(&wgpu_ds_view_desc, sizeof(wgpu_ds_view_desc)); @@ -14508,49 +14429,49 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pass(_sg_pass_t* pass, _sg_imag wgpu_ds_view_desc.mipLevelCount = 1; wgpu_ds_view_desc.baseArrayLayer = (uint32_t) ds_desc->slice; wgpu_ds_view_desc.arrayLayerCount = 1; - pass->wgpu.ds_att.view = wgpuTextureCreateView(ds_img->wgpu.tex, &wgpu_ds_view_desc); - if (0 == pass->wgpu.ds_att.view) { - _SG_ERROR(WGPU_PASS_CREATE_TEXTURE_VIEW_FAILED); + atts->wgpu.depth_stencil.view = wgpuTextureCreateView(ds_img->wgpu.tex, &wgpu_ds_view_desc); + if (0 == atts->wgpu.depth_stencil.view) { + _SG_ERROR(WGPU_ATTACHMENTS_CREATE_TEXTURE_VIEW_FAILED); return SG_RESOURCESTATE_FAILED; } } return SG_RESOURCESTATE_VALID; } -_SOKOL_PRIVATE void _sg_wgpu_discard_pass(_sg_pass_t* pass) { - SOKOL_ASSERT(pass); - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - if (pass->wgpu.color_atts[i].view) { - wgpuTextureViewRelease(pass->wgpu.color_atts[i].view); - pass->wgpu.color_atts[i].view = 0; +_SOKOL_PRIVATE void _sg_wgpu_discard_attachments(_sg_attachments_t* atts) { + SOKOL_ASSERT(atts); + for (int i = 0; i < atts->cmn.num_colors; i++) { + if (atts->wgpu.colors[i].view) { + wgpuTextureViewRelease(atts->wgpu.colors[i].view); + atts->wgpu.colors[i].view = 0; } - if (pass->wgpu.resolve_atts[i].view) { - wgpuTextureViewRelease(pass->wgpu.resolve_atts[i].view); - pass->wgpu.resolve_atts[i].view = 0; + if (atts->wgpu.resolves[i].view) { + wgpuTextureViewRelease(atts->wgpu.resolves[i].view); + atts->wgpu.resolves[i].view = 0; } } - if (pass->wgpu.ds_att.view) { - wgpuTextureViewRelease(pass->wgpu.ds_att.view); - pass->wgpu.ds_att.view = 0; + if (atts->wgpu.depth_stencil.view) { + wgpuTextureViewRelease(atts->wgpu.depth_stencil.view); + atts->wgpu.depth_stencil.view = 0; } } -_SOKOL_PRIVATE _sg_image_t* _sg_wgpu_pass_color_image(const _sg_pass_t* pass, int index) { - SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); +_SOKOL_PRIVATE _sg_image_t* _sg_wgpu_attachments_color_image(const _sg_attachments_t* atts, int index) { + SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); // NOTE: may return null - return pass->wgpu.color_atts[index].image; + return atts->wgpu.colors[index].image; } -_SOKOL_PRIVATE _sg_image_t* _sg_wgpu_pass_resolve_image(const _sg_pass_t* pass, int index) { - SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); +_SOKOL_PRIVATE _sg_image_t* _sg_wgpu_attachments_resolve_image(const _sg_attachments_t* atts, int index) { + SOKOL_ASSERT(atts && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); // NOTE: may return null - return pass->wgpu.resolve_atts[index].image; + return atts->wgpu.resolves[index].image; } -_SOKOL_PRIVATE _sg_image_t* _sg_wgpu_pass_ds_image(const _sg_pass_t* pass) { +_SOKOL_PRIVATE _sg_image_t* _sg_wgpu_attachments_ds_image(const _sg_attachments_t* atts) { // NOTE: may return null - SOKOL_ASSERT(pass); - return pass->wgpu.ds_att.image; + SOKOL_ASSERT(atts); + return atts->wgpu.depth_stencil.image; } _SOKOL_PRIVATE void _sg_wgpu_init_color_att(WGPURenderPassColorAttachment* wgpu_att, const sg_color_attachment_action* action, WGPUTextureView color_view, WGPUTextureView resolve_view) { @@ -14581,17 +14502,15 @@ _SOKOL_PRIVATE void _sg_wgpu_init_ds_att(WGPURenderPassDepthStencilAttachment* w wgpu_att->stencilReadOnly = false; } -_SOKOL_PRIVATE void _sg_wgpu_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { - SOKOL_ASSERT(action); - SOKOL_ASSERT(!_sg.wgpu.in_pass); +_SOKOL_PRIVATE void _sg_wgpu_begin_pass(const sg_pass* pass) { + SOKOL_ASSERT(pass); SOKOL_ASSERT(_sg.wgpu.cmd_enc); SOKOL_ASSERT(_sg.wgpu.dev); - SOKOL_ASSERT(_sg.wgpu.render_view_cb || _sg.wgpu.render_view_userdata_cb); - SOKOL_ASSERT(_sg.wgpu.resolve_view_cb || _sg.wgpu.resolve_view_userdata_cb); - SOKOL_ASSERT(_sg.wgpu.depth_stencil_view_cb || _sg.wgpu.depth_stencil_view_userdata_cb); - _sg.wgpu.in_pass = true; - _sg.wgpu.cur_width = w; - _sg.wgpu.cur_height = h; + + const _sg_attachments_t* atts = _sg.cur_pass.atts; + const sg_swapchain* swapchain = &pass->swapchain; + const sg_pass_action* action = &pass->action; + _sg.wgpu.cur_pipeline = 0; _sg.wgpu.cur_pipeline_id.id = SG_INVALID_ID; @@ -14601,28 +14520,30 @@ _SOKOL_PRIVATE void _sg_wgpu_begin_pass(_sg_pass_t* pass, const sg_pass_action* _sg_clear(&wgpu_pass_desc, sizeof(wgpu_pass_desc)); _sg_clear(&wgpu_color_att, sizeof(wgpu_color_att)); _sg_clear(&wgpu_ds_att, sizeof(wgpu_ds_att)); - if (pass) { - SOKOL_ASSERT(pass->slot.state == SG_RESOURCESTATE_VALID); - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - _sg_wgpu_init_color_att(&wgpu_color_att[i], &action->colors[i], pass->wgpu.color_atts[i].view, pass->wgpu.resolve_atts[i].view); + wgpu_pass_desc.label = pass->label; + if (atts) { + SOKOL_ASSERT(atts->slot.state == SG_RESOURCESTATE_VALID); + for (int i = 0; i < atts->cmn.num_colors; i++) { + _sg_wgpu_init_color_att(&wgpu_color_att[i], &action->colors[i], atts->wgpu.colors[i].view, atts->wgpu.resolves[i].view); } - wgpu_pass_desc.colorAttachmentCount = (size_t)pass->cmn.num_color_atts; + wgpu_pass_desc.colorAttachmentCount = (size_t)atts->cmn.num_colors; wgpu_pass_desc.colorAttachments = &wgpu_color_att[0]; - if (pass->wgpu.ds_att.image) { - _sg_wgpu_init_ds_att(&wgpu_ds_att, action, pass->wgpu.ds_att.image->cmn.pixel_format, pass->wgpu.ds_att.view); + if (atts->wgpu.depth_stencil.image) { + _sg_wgpu_init_ds_att(&wgpu_ds_att, action, atts->wgpu.depth_stencil.image->cmn.pixel_format, atts->wgpu.depth_stencil.view); wgpu_pass_desc.depthStencilAttachment = &wgpu_ds_att; } } else { - WGPUTextureView wgpu_color_view = _sg.wgpu.render_view_cb ? _sg.wgpu.render_view_cb() : _sg.wgpu.render_view_userdata_cb(_sg.wgpu.user_data); - WGPUTextureView wgpu_resolve_view = _sg.wgpu.resolve_view_cb ? _sg.wgpu.resolve_view_cb() : _sg.wgpu.resolve_view_userdata_cb(_sg.wgpu.user_data); - WGPUTextureView wgpu_depth_stencil_view = _sg.wgpu.depth_stencil_view_cb ? _sg.wgpu.depth_stencil_view_cb() : _sg.wgpu.depth_stencil_view_userdata_cb(_sg.wgpu.user_data); + WGPUTextureView wgpu_color_view = (WGPUTextureView) swapchain->wgpu.render_view; + WGPUTextureView wgpu_resolve_view = (WGPUTextureView) swapchain->wgpu.resolve_view; + WGPUTextureView wgpu_depth_stencil_view = (WGPUTextureView) swapchain->wgpu.depth_stencil_view; _sg_wgpu_init_color_att(&wgpu_color_att[0], &action->colors[0], wgpu_color_view, wgpu_resolve_view); wgpu_pass_desc.colorAttachmentCount = 1; wgpu_pass_desc.colorAttachments = &wgpu_color_att[0]; if (wgpu_depth_stencil_view) { - _sg_wgpu_init_ds_att(&wgpu_ds_att, action, _sg.desc.context.depth_format, wgpu_depth_stencil_view); + SOKOL_ASSERT(swapchain->depth_format > SG_PIXELFORMAT_NONE); + _sg_wgpu_init_ds_att(&wgpu_ds_att, action, swapchain->depth_format, wgpu_depth_stencil_view); + wgpu_pass_desc.depthStencilAttachment = &wgpu_ds_att; } - wgpu_pass_desc.depthStencilAttachment = &wgpu_ds_att; } _sg.wgpu.pass_enc = wgpuCommandEncoderBeginRenderPass(_sg.wgpu.cmd_enc, &wgpu_pass_desc); SOKOL_ASSERT(_sg.wgpu.pass_enc); @@ -14637,16 +14558,14 @@ _SOKOL_PRIVATE void _sg_wgpu_begin_pass(_sg_pass_t* pass, const sg_pass_action* } _SOKOL_PRIVATE void _sg_wgpu_end_pass(void) { - SOKOL_ASSERT(_sg.wgpu.in_pass); - SOKOL_ASSERT(_sg.wgpu.pass_enc); - _sg.wgpu.in_pass = false; - wgpuRenderPassEncoderEnd(_sg.wgpu.pass_enc); - wgpuRenderPassEncoderRelease(_sg.wgpu.pass_enc); - _sg.wgpu.pass_enc = 0; + if (_sg.wgpu.pass_enc) { + wgpuRenderPassEncoderEnd(_sg.wgpu.pass_enc); + wgpuRenderPassEncoderRelease(_sg.wgpu.pass_enc); + _sg.wgpu.pass_enc = 0; + } } _SOKOL_PRIVATE void _sg_wgpu_commit(void) { - SOKOL_ASSERT(!_sg.wgpu.in_pass); SOKOL_ASSERT(_sg.wgpu.cmd_enc); _sg_wgpu_uniform_buffer_on_commit(); @@ -14668,26 +14587,24 @@ _SOKOL_PRIVATE void _sg_wgpu_commit(void) { } _SOKOL_PRIVATE void _sg_wgpu_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_sg.wgpu.in_pass); SOKOL_ASSERT(_sg.wgpu.pass_enc); // FIXME FIXME FIXME: CLIPPING THE VIEWPORT HERE IS WRONG!!! // (but currently required because WebGPU insists that the viewport rectangle must be // fully contained inside the framebuffer, but this doesn't make any sense, and also // isn't required by the backend APIs) - const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.wgpu.cur_width, _sg.wgpu.cur_height); + const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.cur_pass.width, _sg.cur_pass.height); float xf = (float) clip.x; - float yf = (float) (origin_top_left ? clip.y : (_sg.wgpu.cur_height - (clip.y + clip.h))); + float yf = (float) (origin_top_left ? clip.y : (_sg.cur_pass.height - (clip.y + clip.h))); float wf = (float) clip.w; float hf = (float) clip.h; wgpuRenderPassEncoderSetViewport(_sg.wgpu.pass_enc, xf, yf, wf, hf, 0.0f, 1.0f); } _SOKOL_PRIVATE void _sg_wgpu_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { - SOKOL_ASSERT(_sg.wgpu.in_pass); SOKOL_ASSERT(_sg.wgpu.pass_enc); - const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.wgpu.cur_width, _sg.wgpu.cur_height); + const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.cur_pass.width, _sg.cur_pass.height); uint32_t sx = (uint32_t) clip.x; - uint32_t sy = (uint32_t) (origin_top_left ? clip.y : (_sg.wgpu.cur_height - (clip.y + clip.h))); + uint32_t sy = (uint32_t) (origin_top_left ? clip.y : (_sg.cur_pass.height - (clip.y + clip.h))); uint32_t sw = (uint32_t) clip.w; uint32_t sh = (uint32_t) clip.h; wgpuRenderPassEncoderSetScissorRect(_sg.wgpu.pass_enc, sx, sy, sw, sh); @@ -14696,7 +14613,6 @@ _SOKOL_PRIVATE void _sg_wgpu_apply_scissor_rect(int x, int y, int w, int h, bool _SOKOL_PRIVATE void _sg_wgpu_apply_pipeline(_sg_pipeline_t* pip) { SOKOL_ASSERT(pip); SOKOL_ASSERT(pip->wgpu.pip); - SOKOL_ASSERT(_sg.wgpu.in_pass); SOKOL_ASSERT(_sg.wgpu.pass_enc); _sg.wgpu.use_indexed_draw = (pip->cmn.index_type != SG_INDEXTYPE_NONE); _sg.wgpu.cur_pipeline = pip; @@ -14707,7 +14623,6 @@ _SOKOL_PRIVATE void _sg_wgpu_apply_pipeline(_sg_pipeline_t* pip) { } _SOKOL_PRIVATE bool _sg_wgpu_apply_bindings(_sg_bindings_t* bnd) { - SOKOL_ASSERT(_sg.wgpu.in_pass); SOKOL_ASSERT(_sg.wgpu.pass_enc); SOKOL_ASSERT(bnd); SOKOL_ASSERT(bnd->pip->shader && (bnd->pip->cmn.shader_id.id == bnd->pip->shader->slot.id)); @@ -14720,7 +14635,6 @@ _SOKOL_PRIVATE bool _sg_wgpu_apply_bindings(_sg_bindings_t* bnd) { _SOKOL_PRIVATE void _sg_wgpu_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { const uint32_t alignment = _sg.wgpu.limits.limits.minUniformBufferOffsetAlignment; - SOKOL_ASSERT(_sg.wgpu.in_pass); SOKOL_ASSERT(_sg.wgpu.pass_enc); SOKOL_ASSERT(_sg.wgpu.uniform.staging); SOKOL_ASSERT((_sg.wgpu.uniform.offset + data->size) <= _sg.wgpu.uniform.num_bytes); @@ -14744,7 +14658,6 @@ _SOKOL_PRIVATE void _sg_wgpu_apply_uniforms(sg_shader_stage stage_index, int ub_ } _SOKOL_PRIVATE void _sg_wgpu_draw(int base_element, int num_elements, int num_instances) { - SOKOL_ASSERT(_sg.wgpu.in_pass); SOKOL_ASSERT(_sg.wgpu.pass_enc); SOKOL_ASSERT(_sg.wgpu.cur_pipeline && (_sg.wgpu.cur_pipeline->slot.id == _sg.wgpu.cur_pipeline_id.id)); if (SG_INDEXTYPE_NONE != _sg.wgpu.cur_pipeline->cmn.index_type) { @@ -14827,54 +14740,6 @@ static inline void _sg_reset_state_cache(void) { #endif } -static inline void _sg_activate_context(_sg_context_t* ctx) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_activate_context(ctx); - #elif defined(SOKOL_METAL) - _sg_mtl_activate_context(ctx); - #elif defined(SOKOL_D3D11) - _sg_d3d11_activate_context(ctx); - #elif defined(SOKOL_WGPU) - _sg_wgpu_activate_context(ctx); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_activate_context(ctx); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline sg_resource_state _sg_create_context(_sg_context_t* ctx) { - #if defined(_SOKOL_ANY_GL) - return _sg_gl_create_context(ctx); - #elif defined(SOKOL_METAL) - return _sg_mtl_create_context(ctx); - #elif defined(SOKOL_D3D11) - return _sg_d3d11_create_context(ctx); - #elif defined(SOKOL_WGPU) - return _sg_wgpu_create_context(ctx); - #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_create_context(ctx); - #else - #error("INVALID BACKEND"); - #endif -} - -static inline void _sg_discard_context(_sg_context_t* ctx) { - #if defined(_SOKOL_ANY_GL) - _sg_gl_discard_context(ctx); - #elif defined(SOKOL_METAL) - _sg_mtl_discard_context(ctx); - #elif defined(SOKOL_D3D11) - _sg_d3d11_discard_context(ctx); - #elif defined(SOKOL_WGPU) - _sg_wgpu_discard_context(ctx); - #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_discard_context(ctx); - #else - #error("INVALID BACKEND"); - #endif -} - static inline sg_resource_state _sg_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { #if defined(_SOKOL_ANY_GL) return _sg_gl_create_buffer(buf, desc); @@ -15035,97 +14900,97 @@ static inline void _sg_discard_pipeline(_sg_pipeline_t* pip) { #endif } -static inline sg_resource_state _sg_create_pass(_sg_pass_t* pass, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_image, const sg_pass_desc* desc) { +static inline sg_resource_state _sg_create_attachments(_sg_attachments_t* atts, _sg_image_t** color_images, _sg_image_t** resolve_images, _sg_image_t* ds_image, const sg_attachments_desc* desc) { #if defined(_SOKOL_ANY_GL) - return _sg_gl_create_pass(pass, color_images, resolve_images, ds_image, desc); + return _sg_gl_create_attachments(atts, color_images, resolve_images, ds_image, desc); #elif defined(SOKOL_METAL) - return _sg_mtl_create_pass(pass, color_images, resolve_images, ds_image, desc); + return _sg_mtl_create_attachments(atts, color_images, resolve_images, ds_image, desc); #elif defined(SOKOL_D3D11) - return _sg_d3d11_create_pass(pass, color_images, resolve_images, ds_image, desc); + return _sg_d3d11_create_attachments(atts, color_images, resolve_images, ds_image, desc); #elif defined(SOKOL_WGPU) - return _sg_wgpu_create_pass(pass, color_images, resolve_images, ds_image, desc); + return _sg_wgpu_create_attachments(atts, color_images, resolve_images, ds_image, desc); #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_create_pass(pass, color_images, resolve_images, ds_image, desc); + return _sg_dummy_create_attachments(atts, color_images, resolve_images, ds_image, desc); #else #error("INVALID BACKEND"); #endif } -static inline void _sg_discard_pass(_sg_pass_t* pass) { +static inline void _sg_discard_attachments(_sg_attachments_t* atts) { #if defined(_SOKOL_ANY_GL) - _sg_gl_discard_pass(pass); + _sg_gl_discard_attachments(atts); #elif defined(SOKOL_METAL) - _sg_mtl_discard_pass(pass); + _sg_mtl_discard_attachments(atts); #elif defined(SOKOL_D3D11) - _sg_d3d11_discard_pass(pass); + _sg_d3d11_discard_attachments(atts); #elif defined(SOKOL_WGPU) - return _sg_wgpu_discard_pass(pass); + return _sg_wgpu_discard_attachments(atts); #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_discard_pass(pass); + _sg_dummy_discard_attachments(atts); #else #error("INVALID BACKEND"); #endif } -static inline _sg_image_t* _sg_pass_color_image(const _sg_pass_t* pass, int index) { +static inline _sg_image_t* _sg_attachments_color_image(const _sg_attachments_t* atts, int index) { #if defined(_SOKOL_ANY_GL) - return _sg_gl_pass_color_image(pass, index); + return _sg_gl_attachments_color_image(atts, index); #elif defined(SOKOL_METAL) - return _sg_mtl_pass_color_image(pass, index); + return _sg_mtl_attachments_color_image(atts, index); #elif defined(SOKOL_D3D11) - return _sg_d3d11_pass_color_image(pass, index); + return _sg_d3d11_attachments_color_image(atts, index); #elif defined(SOKOL_WGPU) - return _sg_wgpu_pass_color_image(pass, index); + return _sg_wgpu_attachments_color_image(atts, index); #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_pass_color_image(pass, index); + return _sg_dummy_attachments_color_image(atts, index); #else #error("INVALID BACKEND"); #endif } -static inline _sg_image_t* _sg_pass_resolve_image(const _sg_pass_t* pass, int index) { +static inline _sg_image_t* _sg_attachments_resolve_image(const _sg_attachments_t* atts, int index) { #if defined(_SOKOL_ANY_GL) - return _sg_gl_pass_resolve_image(pass, index); + return _sg_gl_attachments_resolve_image(atts, index); #elif defined(SOKOL_METAL) - return _sg_mtl_pass_resolve_image(pass, index); + return _sg_mtl_attachments_resolve_image(atts, index); #elif defined(SOKOL_D3D11) - return _sg_d3d11_pass_resolve_image(pass, index); + return _sg_d3d11_attachments_resolve_image(atts, index); #elif defined(SOKOL_WGPU) - return _sg_wgpu_pass_resolve_image(pass, index); + return _sg_wgpu_attachments_resolve_image(atts, index); #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_pass_resolve_image(pass, index); + return _sg_dummy_attachments_resolve_image(atts, index); #else #error("INVALID BACKEND"); #endif } -static inline _sg_image_t* _sg_pass_ds_image(const _sg_pass_t* pass) { +static inline _sg_image_t* _sg_attachments_ds_image(const _sg_attachments_t* atts) { #if defined(_SOKOL_ANY_GL) - return _sg_gl_pass_ds_image(pass); + return _sg_gl_attachments_ds_image(atts); #elif defined(SOKOL_METAL) - return _sg_mtl_pass_ds_image(pass); + return _sg_mtl_attachments_ds_image(atts); #elif defined(SOKOL_D3D11) - return _sg_d3d11_pass_ds_image(pass); + return _sg_d3d11_attachments_ds_image(atts); #elif defined(SOKOL_WGPU) - return _sg_wgpu_pass_ds_image(pass); + return _sg_wgpu_attachments_ds_image(atts); #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_pass_ds_image(pass); + return _sg_dummy_attachments_ds_image(atts); #else #error("INVALID BACKEND"); #endif } -static inline void _sg_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { +static inline void _sg_begin_pass(const sg_pass* pass) { #if defined(_SOKOL_ANY_GL) - _sg_gl_begin_pass(pass, action, w, h); + _sg_gl_begin_pass(pass); #elif defined(SOKOL_METAL) - _sg_mtl_begin_pass(pass, action, w, h); + _sg_mtl_begin_pass(pass); #elif defined(SOKOL_D3D11) - _sg_d3d11_begin_pass(pass, action, w, h); + _sg_d3d11_begin_pass(pass); #elif defined(SOKOL_WGPU) - _sg_wgpu_begin_pass(pass, action, w, h); + _sg_wgpu_begin_pass(pass); #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_begin_pass(pass, action, w, h); + _sg_dummy_begin_pass(pass); #else #error("INVALID BACKEND"); #endif @@ -15392,7 +15257,7 @@ _SOKOL_PRIVATE void _sg_reset_slot(_sg_slot_t* slot) { _SOKOL_PRIVATE void _sg_reset_buffer_to_alloc_state(_sg_buffer_t* buf) { SOKOL_ASSERT(buf); _sg_slot_t slot = buf->slot; - _sg_clear(buf, sizeof(_sg_buffer_t)); + _sg_clear(buf, sizeof(*buf)); buf->slot = slot; buf->slot.state = SG_RESOURCESTATE_ALLOC; } @@ -15400,7 +15265,7 @@ _SOKOL_PRIVATE void _sg_reset_buffer_to_alloc_state(_sg_buffer_t* buf) { _SOKOL_PRIVATE void _sg_reset_image_to_alloc_state(_sg_image_t* img) { SOKOL_ASSERT(img); _sg_slot_t slot = img->slot; - _sg_clear(img, sizeof(_sg_image_t)); + _sg_clear(img, sizeof(*img)); img->slot = slot; img->slot.state = SG_RESOURCESTATE_ALLOC; } @@ -15408,7 +15273,7 @@ _SOKOL_PRIVATE void _sg_reset_image_to_alloc_state(_sg_image_t* img) { _SOKOL_PRIVATE void _sg_reset_sampler_to_alloc_state(_sg_sampler_t* smp) { SOKOL_ASSERT(smp); _sg_slot_t slot = smp->slot; - _sg_clear(smp, sizeof(_sg_sampler_t)); + _sg_clear(smp, sizeof(*smp)); smp->slot = slot; smp->slot.state = SG_RESOURCESTATE_ALLOC; } @@ -15416,7 +15281,7 @@ _SOKOL_PRIVATE void _sg_reset_sampler_to_alloc_state(_sg_sampler_t* smp) { _SOKOL_PRIVATE void _sg_reset_shader_to_alloc_state(_sg_shader_t* shd) { SOKOL_ASSERT(shd); _sg_slot_t slot = shd->slot; - _sg_clear(shd, sizeof(_sg_shader_t)); + _sg_clear(shd, sizeof(*shd)); shd->slot = slot; shd->slot.state = SG_RESOURCESTATE_ALLOC; } @@ -15424,25 +15289,17 @@ _SOKOL_PRIVATE void _sg_reset_shader_to_alloc_state(_sg_shader_t* shd) { _SOKOL_PRIVATE void _sg_reset_pipeline_to_alloc_state(_sg_pipeline_t* pip) { SOKOL_ASSERT(pip); _sg_slot_t slot = pip->slot; - _sg_clear(pip, sizeof(_sg_pipeline_t)); + _sg_clear(pip, sizeof(*pip)); pip->slot = slot; pip->slot.state = SG_RESOURCESTATE_ALLOC; } -_SOKOL_PRIVATE void _sg_reset_pass_to_alloc_state(_sg_pass_t* pass) { - SOKOL_ASSERT(pass); - _sg_slot_t slot = pass->slot; - _sg_clear(pass, sizeof(_sg_pass_t)); - pass->slot = slot; - pass->slot.state = SG_RESOURCESTATE_ALLOC; -} - -_SOKOL_PRIVATE void _sg_reset_context_to_alloc_state(_sg_context_t* ctx) { - SOKOL_ASSERT(ctx); - _sg_slot_t slot = ctx->slot; - _sg_clear(ctx, sizeof(_sg_context_t)); - ctx->slot = slot; - ctx->slot.state = SG_RESOURCESTATE_ALLOC; +_SOKOL_PRIVATE void _sg_reset_attachments_to_alloc_state(_sg_attachments_t* atts) { + SOKOL_ASSERT(atts); + _sg_slot_t slot = atts->slot; + _sg_clear(atts, sizeof(*atts)); + atts->slot = slot; + atts->slot.state = SG_RESOURCESTATE_ALLOC; } _SOKOL_PRIVATE void _sg_setup_pools(_sg_pools_t* p, const sg_desc* desc) { @@ -15474,28 +15331,21 @@ _SOKOL_PRIVATE void _sg_setup_pools(_sg_pools_t* p, const sg_desc* desc) { size_t pipeline_pool_byte_size = sizeof(_sg_pipeline_t) * (size_t)p->pipeline_pool.size; p->pipelines = (_sg_pipeline_t*) _sg_malloc_clear(pipeline_pool_byte_size); - SOKOL_ASSERT((desc->pass_pool_size > 0) && (desc->pass_pool_size < _SG_MAX_POOL_SIZE)); - _sg_init_pool(&p->pass_pool, desc->pass_pool_size); - size_t pass_pool_byte_size = sizeof(_sg_pass_t) * (size_t)p->pass_pool.size; - p->passes = (_sg_pass_t*) _sg_malloc_clear(pass_pool_byte_size); - - SOKOL_ASSERT((desc->context_pool_size > 0) && (desc->context_pool_size < _SG_MAX_POOL_SIZE)); - _sg_init_pool(&p->context_pool, desc->context_pool_size); - size_t context_pool_byte_size = sizeof(_sg_context_t) * (size_t)p->context_pool.size; - p->contexts = (_sg_context_t*) _sg_malloc_clear(context_pool_byte_size); + SOKOL_ASSERT((desc->attachments_pool_size > 0) && (desc->attachments_pool_size < _SG_MAX_POOL_SIZE)); + _sg_init_pool(&p->attachments_pool, desc->attachments_pool_size); + size_t attachments_pool_byte_size = sizeof(_sg_attachments_t) * (size_t)p->attachments_pool.size; + p->attachments = (_sg_attachments_t*) _sg_malloc_clear(attachments_pool_byte_size); } _SOKOL_PRIVATE void _sg_discard_pools(_sg_pools_t* p) { SOKOL_ASSERT(p); - _sg_free(p->contexts); p->contexts = 0; - _sg_free(p->passes); p->passes = 0; + _sg_free(p->attachments); p->attachments = 0; _sg_free(p->pipelines); p->pipelines = 0; _sg_free(p->shaders); p->shaders = 0; _sg_free(p->samplers); p->samplers = 0; _sg_free(p->images); p->images = 0; _sg_free(p->buffers); p->buffers = 0; - _sg_discard_pool(&p->context_pool); - _sg_discard_pool(&p->pass_pool); + _sg_discard_pool(&p->attachments_pool); _sg_discard_pool(&p->pipeline_pool); _sg_discard_pool(&p->shader_pool); _sg_discard_pool(&p->sampler_pool); @@ -15568,18 +15418,11 @@ _SOKOL_PRIVATE _sg_pipeline_t* _sg_pipeline_at(const _sg_pools_t* p, uint32_t pi return &p->pipelines[slot_index]; } -_SOKOL_PRIVATE _sg_pass_t* _sg_pass_at(const _sg_pools_t* p, uint32_t pass_id) { - SOKOL_ASSERT(p && (SG_INVALID_ID != pass_id)); - int slot_index = _sg_slot_index(pass_id); - SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->pass_pool.size)); - return &p->passes[slot_index]; -} - -_SOKOL_PRIVATE _sg_context_t* _sg_context_at(const _sg_pools_t* p, uint32_t context_id) { - SOKOL_ASSERT(p && (SG_INVALID_ID != context_id)); - int slot_index = _sg_slot_index(context_id); - SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->context_pool.size)); - return &p->contexts[slot_index]; +_SOKOL_PRIVATE _sg_attachments_t* _sg_attachments_at(const _sg_pools_t* p, uint32_t atts_id) { + SOKOL_ASSERT(p && (SG_INVALID_ID != atts_id)); + int slot_index = _sg_slot_index(atts_id); + SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->attachments_pool.size)); + return &p->attachments[slot_index]; } // returns pointer to resource with matching id check, may return 0 @@ -15635,29 +15478,18 @@ _SOKOL_PRIVATE _sg_pipeline_t* _sg_lookup_pipeline(const _sg_pools_t* p, uint32_ return 0; } -_SOKOL_PRIVATE _sg_pass_t* _sg_lookup_pass(const _sg_pools_t* p, uint32_t pass_id) { - SOKOL_ASSERT(p); - if (SG_INVALID_ID != pass_id) { - _sg_pass_t* pass = _sg_pass_at(p, pass_id); - if (pass->slot.id == pass_id) { - return pass; - } - } - return 0; -} - -_SOKOL_PRIVATE _sg_context_t* _sg_lookup_context(const _sg_pools_t* p, uint32_t ctx_id) { +_SOKOL_PRIVATE _sg_attachments_t* _sg_lookup_attachments(const _sg_pools_t* p, uint32_t atts_id) { SOKOL_ASSERT(p); - if (SG_INVALID_ID != ctx_id) { - _sg_context_t* ctx = _sg_context_at(p, ctx_id); - if (ctx->slot.id == ctx_id) { - return ctx; + if (SG_INVALID_ID != atts_id) { + _sg_attachments_t* atts = _sg_attachments_at(p, atts_id); + if (atts->slot.id == atts_id) { + return atts; } } return 0; } -_SOKOL_PRIVATE void _sg_discard_all_resources(_sg_pools_t* p, uint32_t ctx_id) { +_SOKOL_PRIVATE void _sg_discard_all_resources(_sg_pools_t* p) { /* this is a bit dumb since it loops over all pool slots to find the occupied slots, on the other hand it is only ever executed at shutdown @@ -15666,51 +15498,39 @@ _SOKOL_PRIVATE void _sg_discard_all_resources(_sg_pools_t* p, uint32_t ctx_id) { and the resource slots not be cleared! */ for (int i = 1; i < p->buffer_pool.size; i++) { - if (p->buffers[i].slot.ctx_id == ctx_id) { - sg_resource_state state = p->buffers[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_buffer(&p->buffers[i]); - } + sg_resource_state state = p->buffers[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_discard_buffer(&p->buffers[i]); } } for (int i = 1; i < p->image_pool.size; i++) { - if (p->images[i].slot.ctx_id == ctx_id) { - sg_resource_state state = p->images[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_image(&p->images[i]); - } + sg_resource_state state = p->images[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_discard_image(&p->images[i]); } } for (int i = 1; i < p->sampler_pool.size; i++) { - if (p->samplers[i].slot.ctx_id == ctx_id) { - sg_resource_state state = p->samplers[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_sampler(&p->samplers[i]); - } + sg_resource_state state = p->samplers[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_discard_sampler(&p->samplers[i]); } } for (int i = 1; i < p->shader_pool.size; i++) { - if (p->shaders[i].slot.ctx_id == ctx_id) { - sg_resource_state state = p->shaders[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_shader(&p->shaders[i]); - } + sg_resource_state state = p->shaders[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_discard_shader(&p->shaders[i]); } } for (int i = 1; i < p->pipeline_pool.size; i++) { - if (p->pipelines[i].slot.ctx_id == ctx_id) { - sg_resource_state state = p->pipelines[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_pipeline(&p->pipelines[i]); - } + sg_resource_state state = p->pipelines[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_discard_pipeline(&p->pipelines[i]); } } - for (int i = 1; i < p->pass_pool.size; i++) { - if (p->passes[i].slot.ctx_id == ctx_id) { - sg_resource_state state = p->passes[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_discard_pass(&p->passes[i]); - } + for (int i = 1; i < p->attachments_pool.size; i++) { + sg_resource_state state = p->attachments[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_discard_attachments(&p->attachments[i]); } } } @@ -16093,7 +15913,7 @@ _SOKOL_PRIVATE bool _sg_validate_pipeline_desc(const sg_pipeline_desc* desc) { #endif } -_SOKOL_PRIVATE bool _sg_validate_pass_desc(const sg_pass_desc* desc) { +_SOKOL_PRIVATE bool _sg_validate_attachments_desc(const sg_attachments_desc* desc) { #if !defined(SOKOL_DEBUG) _SOKOL_UNUSED(desc); return true; @@ -16103,99 +15923,99 @@ _SOKOL_PRIVATE bool _sg_validate_pass_desc(const sg_pass_desc* desc) { } SOKOL_ASSERT(desc); _sg_validate_begin(); - _SG_VALIDATE(desc->_start_canary == 0, VALIDATE_PASSDESC_CANARY); - _SG_VALIDATE(desc->_end_canary == 0, VALIDATE_PASSDESC_CANARY); + _SG_VALIDATE(desc->_start_canary == 0, VALIDATE_ATTACHMENTSDESC_CANARY); + _SG_VALIDATE(desc->_end_canary == 0, VALIDATE_ATTACHMENTSDESC_CANARY); bool atts_cont = true; int color_width = -1, color_height = -1, color_sample_count = -1; bool has_color_atts = false; for (int att_index = 0; att_index < SG_MAX_COLOR_ATTACHMENTS; att_index++) { - const sg_pass_attachment_desc* att = &desc->color_attachments[att_index]; + const sg_attachment_desc* att = &desc->colors[att_index]; if (att->image.id == SG_INVALID_ID) { atts_cont = false; continue; } - _SG_VALIDATE(atts_cont, VALIDATE_PASSDESC_NO_CONT_COLOR_ATTS); + _SG_VALIDATE(atts_cont, VALIDATE_ATTACHMENTSDESC_NO_CONT_COLOR_ATTS); has_color_atts = true; const _sg_image_t* img = _sg_lookup_image(&_sg.pools, att->image.id); - _SG_VALIDATE(img, VALIDATE_PASSDESC_IMAGE); + _SG_VALIDATE(img, VALIDATE_ATTACHMENTSDESC_IMAGE); if (0 != img) { - _SG_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_PASSDESC_IMAGE); - _SG_VALIDATE(img->cmn.render_target, VALIDATE_PASSDESC_IMAGE_NO_RT); - _SG_VALIDATE(att->mip_level < img->cmn.num_mipmaps, VALIDATE_PASSDESC_MIPLEVEL); + _SG_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_ATTACHMENTSDESC_IMAGE); + _SG_VALIDATE(img->cmn.render_target, VALIDATE_ATTACHMENTSDESC_IMAGE_NO_RT); + _SG_VALIDATE(att->mip_level < img->cmn.num_mipmaps, VALIDATE_ATTACHMENTSDESC_MIPLEVEL); if (img->cmn.type == SG_IMAGETYPE_CUBE) { - _SG_VALIDATE(att->slice < 6, VALIDATE_PASSDESC_FACE); + _SG_VALIDATE(att->slice < 6, VALIDATE_ATTACHMENTSDESC_FACE); } else if (img->cmn.type == SG_IMAGETYPE_ARRAY) { - _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_PASSDESC_LAYER); + _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_LAYER); } else if (img->cmn.type == SG_IMAGETYPE_3D) { - _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_PASSDESC_SLICE); + _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_SLICE); } if (att_index == 0) { color_width = _sg_miplevel_dim(img->cmn.width, att->mip_level); color_height = _sg_miplevel_dim(img->cmn.height, att->mip_level); color_sample_count = img->cmn.sample_count; } else { - _SG_VALIDATE(color_width == _sg_miplevel_dim(img->cmn.width, att->mip_level), VALIDATE_PASSDESC_IMAGE_SIZES); - _SG_VALIDATE(color_height == _sg_miplevel_dim(img->cmn.height, att->mip_level), VALIDATE_PASSDESC_IMAGE_SIZES); - _SG_VALIDATE(color_sample_count == img->cmn.sample_count, VALIDATE_PASSDESC_IMAGE_SAMPLE_COUNTS); + _SG_VALIDATE(color_width == _sg_miplevel_dim(img->cmn.width, att->mip_level), VALIDATE_ATTACHMENTSDESC_IMAGE_SIZES); + _SG_VALIDATE(color_height == _sg_miplevel_dim(img->cmn.height, att->mip_level), VALIDATE_ATTACHMENTSDESC_IMAGE_SIZES); + _SG_VALIDATE(color_sample_count == img->cmn.sample_count, VALIDATE_ATTACHMENTSDESC_IMAGE_SAMPLE_COUNTS); } - _SG_VALIDATE(_sg_is_valid_rendertarget_color_format(img->cmn.pixel_format), VALIDATE_PASSDESC_COLOR_INV_PIXELFORMAT); + _SG_VALIDATE(_sg_is_valid_rendertarget_color_format(img->cmn.pixel_format), VALIDATE_ATTACHMENTSDESC_COLOR_INV_PIXELFORMAT); // check resolve attachment - const sg_pass_attachment_desc* res_att = &desc->resolve_attachments[att_index]; + const sg_attachment_desc* res_att = &desc->resolves[att_index]; if (res_att->image.id != SG_INVALID_ID) { // associated color attachment must be MSAA - _SG_VALIDATE(img->cmn.sample_count > 1, VALIDATE_PASSDESC_RESOLVE_COLOR_IMAGE_MSAA); + _SG_VALIDATE(img->cmn.sample_count > 1, VALIDATE_ATTACHMENTSDESC_RESOLVE_COLOR_IMAGE_MSAA); const _sg_image_t* res_img = _sg_lookup_image(&_sg.pools, res_att->image.id); - _SG_VALIDATE(res_img, VALIDATE_PASSDESC_RESOLVE_IMAGE); + _SG_VALIDATE(res_img, VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE); if (res_img != 0) { - _SG_VALIDATE(res_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_PASSDESC_RESOLVE_IMAGE); - _SG_VALIDATE(res_img->cmn.render_target, VALIDATE_PASSDESC_RESOLVE_IMAGE_NO_RT); - _SG_VALIDATE(res_img->cmn.sample_count == 1, VALIDATE_PASSDESC_RESOLVE_SAMPLE_COUNT); - _SG_VALIDATE(res_att->mip_level < res_img->cmn.num_mipmaps, VALIDATE_PASSDESC_RESOLVE_MIPLEVEL); + _SG_VALIDATE(res_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE); + _SG_VALIDATE(res_img->cmn.render_target, VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_NO_RT); + _SG_VALIDATE(res_img->cmn.sample_count == 1, VALIDATE_ATTACHMENTSDESC_RESOLVE_SAMPLE_COUNT); + _SG_VALIDATE(res_att->mip_level < res_img->cmn.num_mipmaps, VALIDATE_ATTACHMENTSDESC_RESOLVE_MIPLEVEL); if (res_img->cmn.type == SG_IMAGETYPE_CUBE) { - _SG_VALIDATE(res_att->slice < 6, VALIDATE_PASSDESC_RESOLVE_FACE); + _SG_VALIDATE(res_att->slice < 6, VALIDATE_ATTACHMENTSDESC_RESOLVE_FACE); } else if (res_img->cmn.type == SG_IMAGETYPE_ARRAY) { - _SG_VALIDATE(res_att->slice < res_img->cmn.num_slices, VALIDATE_PASSDESC_RESOLVE_LAYER); + _SG_VALIDATE(res_att->slice < res_img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_RESOLVE_LAYER); } else if (res_img->cmn.type == SG_IMAGETYPE_3D) { - _SG_VALIDATE(res_att->slice < res_img->cmn.num_slices, VALIDATE_PASSDESC_RESOLVE_SLICE); + _SG_VALIDATE(res_att->slice < res_img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_RESOLVE_SLICE); } - _SG_VALIDATE(img->cmn.pixel_format == res_img->cmn.pixel_format, VALIDATE_PASSDESC_RESOLVE_IMAGE_FORMAT); - _SG_VALIDATE(color_width == _sg_miplevel_dim(res_img->cmn.width, res_att->mip_level), VALIDATE_PASSDESC_RESOLVE_IMAGE_SIZES); - _SG_VALIDATE(color_height == _sg_miplevel_dim(res_img->cmn.height, res_att->mip_level), VALIDATE_PASSDESC_RESOLVE_IMAGE_SIZES); + _SG_VALIDATE(img->cmn.pixel_format == res_img->cmn.pixel_format, VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_FORMAT); + _SG_VALIDATE(color_width == _sg_miplevel_dim(res_img->cmn.width, res_att->mip_level), VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_SIZES); + _SG_VALIDATE(color_height == _sg_miplevel_dim(res_img->cmn.height, res_att->mip_level), VALIDATE_ATTACHMENTSDESC_RESOLVE_IMAGE_SIZES); } } } } bool has_depth_stencil_att = false; - if (desc->depth_stencil_attachment.image.id != SG_INVALID_ID) { - const sg_pass_attachment_desc* att = &desc->depth_stencil_attachment; + if (desc->depth_stencil.image.id != SG_INVALID_ID) { + const sg_attachment_desc* att = &desc->depth_stencil; const _sg_image_t* img = _sg_lookup_image(&_sg.pools, att->image.id); - _SG_VALIDATE(img, VALIDATE_PASSDESC_DEPTH_IMAGE); + _SG_VALIDATE(img, VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE); has_depth_stencil_att = true; if (img) { - _SG_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_PASSDESC_DEPTH_IMAGE); - _SG_VALIDATE(att->mip_level < img->cmn.num_mipmaps, VALIDATE_PASSDESC_DEPTH_MIPLEVEL); + _SG_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE); + _SG_VALIDATE(att->mip_level < img->cmn.num_mipmaps, VALIDATE_ATTACHMENTSDESC_DEPTH_MIPLEVEL); if (img->cmn.type == SG_IMAGETYPE_CUBE) { - _SG_VALIDATE(att->slice < 6, VALIDATE_PASSDESC_DEPTH_FACE); + _SG_VALIDATE(att->slice < 6, VALIDATE_ATTACHMENTSDESC_DEPTH_FACE); } else if (img->cmn.type == SG_IMAGETYPE_ARRAY) { - _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_PASSDESC_DEPTH_LAYER); + _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_DEPTH_LAYER); } else if (img->cmn.type == SG_IMAGETYPE_3D) { // NOTE: this can't actually happen because of VALIDATE_IMAGEDESC_DEPTH_3D_IMAGE - _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_PASSDESC_DEPTH_SLICE); + _SG_VALIDATE(att->slice < img->cmn.num_slices, VALIDATE_ATTACHMENTSDESC_DEPTH_SLICE); } - _SG_VALIDATE(img->cmn.render_target, VALIDATE_PASSDESC_DEPTH_IMAGE_NO_RT); - _SG_VALIDATE((color_width == -1) || (color_width == _sg_miplevel_dim(img->cmn.width, att->mip_level)), VALIDATE_PASSDESC_DEPTH_IMAGE_SIZES); - _SG_VALIDATE((color_height == -1) || (color_height == _sg_miplevel_dim(img->cmn.height, att->mip_level)), VALIDATE_PASSDESC_DEPTH_IMAGE_SIZES); - _SG_VALIDATE((color_sample_count == -1) || (color_sample_count == img->cmn.sample_count), VALIDATE_PASSDESC_DEPTH_IMAGE_SAMPLE_COUNT); - _SG_VALIDATE(_sg_is_valid_rendertarget_depth_format(img->cmn.pixel_format), VALIDATE_PASSDESC_DEPTH_INV_PIXELFORMAT); + _SG_VALIDATE(img->cmn.render_target, VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_NO_RT); + _SG_VALIDATE((color_width == -1) || (color_width == _sg_miplevel_dim(img->cmn.width, att->mip_level)), VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SIZES); + _SG_VALIDATE((color_height == -1) || (color_height == _sg_miplevel_dim(img->cmn.height, att->mip_level)), VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SIZES); + _SG_VALIDATE((color_sample_count == -1) || (color_sample_count == img->cmn.sample_count), VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SAMPLE_COUNT); + _SG_VALIDATE(_sg_is_valid_rendertarget_depth_format(img->cmn.pixel_format), VALIDATE_ATTACHMENTSDESC_DEPTH_INV_PIXELFORMAT); } } - _SG_VALIDATE(has_color_atts || has_depth_stencil_att, VALIDATE_PASSDESC_NO_ATTACHMENTS); + _SG_VALIDATE(has_color_atts || has_depth_stencil_att, VALIDATE_ATTACHMENTSDESC_NO_ATTACHMENTS); return _sg_validate_end(); #endif } -_SOKOL_PRIVATE bool _sg_validate_begin_pass(_sg_pass_t* pass) { +_SOKOL_PRIVATE bool _sg_validate_begin_pass(const sg_pass* pass) { #if !defined(SOKOL_DEBUG) _SOKOL_UNUSED(pass); return true; @@ -16204,27 +16024,102 @@ _SOKOL_PRIVATE bool _sg_validate_begin_pass(_sg_pass_t* pass) { return true; } _sg_validate_begin(); - _SG_VALIDATE(pass->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_PASS); - - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - const _sg_pass_attachment_t* color_att = &pass->cmn.color_atts[i]; - const _sg_image_t* color_img = _sg_pass_color_image(pass, i); - if (color_img) { - _SG_VALIDATE(color_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE); - _SG_VALIDATE(color_img->slot.id == color_att->image_id.id, VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE); - } - const _sg_pass_attachment_t* resolve_att = &pass->cmn.resolve_atts[i]; - const _sg_image_t* resolve_img = _sg_pass_resolve_image(pass, i); - if (resolve_img) { - _SG_VALIDATE(resolve_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE); - _SG_VALIDATE(resolve_img->slot.id == resolve_att->image_id.id, VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE); + _SG_VALIDATE(pass->_start_canary == 0, VALIDATE_BEGINPASS_CANARY); + _SG_VALIDATE(pass->_end_canary == 0, VALIDATE_BEGINPASS_CANARY); + if (pass->attachments.id == SG_INVALID_ID) { + // this is a swapchain pass + _SG_VALIDATE(pass->swapchain.width > 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_WIDTH); + _SG_VALIDATE(pass->swapchain.height > 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_HEIGHT); + _SG_VALIDATE(pass->swapchain.sample_count > 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_SAMPLECOUNT); + _SG_VALIDATE(pass->swapchain.color_format > SG_PIXELFORMAT_NONE, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_COLORFORMAT); + // NOTE: depth buffer is optional, so depth_format is allowed to be invalid + // NOTE: the GL framebuffer handle may actually be 0 + #if defined(SOKOL_METAL) + _SG_VALIDATE(pass->swapchain.metal.current_drawable != 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_CURRENTDRAWABLE); + if (pass->swapchain.depth_format == SG_PIXELFORMAT_NONE) { + _SG_VALIDATE(pass->swapchain.metal.depth_stencil_texture == 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_DEPTHSTENCILTEXTURE_NOTSET); + } else { + _SG_VALIDATE(pass->swapchain.metal.depth_stencil_texture != 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_DEPTHSTENCILTEXTURE); + } + if (pass->swapchain.sample_count > 1) { + _SG_VALIDATE(pass->swapchain.metal.msaa_color_texture != 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_MSAACOLORTEXTURE); + } else { + _SG_VALIDATE(pass->swapchain.metal.msaa_color_texture == 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_MSAACOLORTEXTURE_NOTSET); + } + #elif defined(SOKOL_D3D11) + _SG_VALIDATE(pass->swapchain.d3d11.render_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RENDERVIEW); + if (pass->swapchain.depth_format == SG_PIXELFORMAT_NONE) { + _SG_VALIDATE(pass->swapchain.d3d11.depth_stencil_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_DEPTHSTENCILVIEW_NOTSET); + } else { + _SG_VALIDATE(pass->swapchain.d3d11.depth_stencil_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_DEPTHSTENCILVIEW); + } + if (pass->swapchain.sample_count > 1) { + _SG_VALIDATE(pass->swapchain.d3d11.resolve_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RESOLVEVIEW); + } else { + _SG_VALIDATE(pass->swapchain.d3d11.resolve_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RESOLVEVIEW_NOTSET); + } + #elif defined(SOKOL_WGPU) + _SG_VALIDATE(pass->swapchain.wgpu.render_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RENDERVIEW); + if (pass->swapchain.depth_format == SG_PIXELFORMAT_NONE) { + _SG_VALIDATE(pass->swapchain.wgpu.depth_stencil_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_DEPTHSTENCILVIEW_NOTSET); + } else { + _SG_VALIDATE(pass->swapchain.wgpu.depth_stencil_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_DEPTHSTENCILVIEW); + } + if (pass->swapchain.sample_count > 1) { + _SG_VALIDATE(pass->swapchain.wgpu.resolve_view != 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RESOLVEVIEW); + } else { + _SG_VALIDATE(pass->swapchain.wgpu.resolve_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RESOLVEVIEW_NOTSET); + } + #endif + } else { + // this is an 'offscreen pass' + const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, pass->attachments.id); + if (atts) { + _SG_VALIDATE(atts->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_ATTACHMENTS_VALID); + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + const _sg_attachment_common_t* color_att = &atts->cmn.colors[i]; + const _sg_image_t* color_img = _sg_attachments_color_image(atts, i); + if (color_img) { + _SG_VALIDATE(color_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE); + _SG_VALIDATE(color_img->slot.id == color_att->image_id.id, VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE); + } + const _sg_attachment_common_t* resolve_att = &atts->cmn.resolves[i]; + const _sg_image_t* resolve_img = _sg_attachments_resolve_image(atts, i); + if (resolve_img) { + _SG_VALIDATE(resolve_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE); + _SG_VALIDATE(resolve_img->slot.id == resolve_att->image_id.id, VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE); + } + } + const _sg_image_t* ds_img = _sg_attachments_ds_image(atts); + if (ds_img) { + const _sg_attachment_common_t* att = &atts->cmn.depth_stencil; + _SG_VALIDATE(ds_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE); + _SG_VALIDATE(ds_img->slot.id == att->image_id.id, VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE); + } + } else { + _SG_VALIDATE(atts != 0, VALIDATE_BEGINPASS_ATTACHMENTS_EXISTS); } - } - const _sg_image_t* ds_img = _sg_pass_ds_image(pass); - if (ds_img) { - const _sg_pass_attachment_t* att = &pass->cmn.ds_att; - _SG_VALIDATE(ds_img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE); - _SG_VALIDATE(ds_img->slot.id == att->image_id.id, VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE); + // swapchain params must be all zero! + _SG_VALIDATE(pass->swapchain.width == 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_WIDTH_NOTSET); + _SG_VALIDATE(pass->swapchain.height == 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_HEIGHT_NOTSET); + _SG_VALIDATE(pass->swapchain.sample_count == 0, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_SAMPLECOUNT_NOTSET); + _SG_VALIDATE(pass->swapchain.color_format == _SG_PIXELFORMAT_DEFAULT, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_COLORFORMAT_NOTSET); + _SG_VALIDATE(pass->swapchain.depth_format == _SG_PIXELFORMAT_DEFAULT, VALIDATE_BEGINPASS_SWAPCHAIN_EXPECT_DEPTHFORMAT_NOTSET); + #if defined(SOKOL_METAL) + _SG_VALIDATE(pass->swapchain.metal.current_drawable == 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_CURRENTDRAWABLE_NOTSET); + _SG_VALIDATE(pass->swapchain.metal.depth_stencil_texture == 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_DEPTHSTENCILTEXTURE_NOTSET); + _SG_VALIDATE(pass->swapchain.metal.msaa_color_texture == 0, VALIDATE_BEGINPASS_SWAPCHAIN_METAL_EXPECT_MSAACOLORTEXTURE_NOTSET); + #elif defined(SOKOL_D3D11) + _SG_VALIDATE(pass->swapchain.d3d11.render_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RENDERVIEW_NOTSET); + _SG_VALIDATE(pass->swapchain.d3d11.depth_stencil_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_DEPTHSTENCILVIEW_NOTSET); + _SG_VALIDATE(pass->swapchain.d3d11.resolve_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_D3D11_EXPECT_RESOLVEVIEW_NOTSET); + #elif defined(SOKOL_WGPU) + _SG_VALIDATE(pass->swapchain.wgpu.render_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RENDERVIEW_NOTSET); + _SG_VALIDATE(pass->swapchain.wgpu.depth_stencil_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_DEPTHSTENCILVIEW_NOTSET); + _SG_VALIDATE(pass->swapchain.wgpu.resolve_view == 0, VALIDATE_BEGINPASS_SWAPCHAIN_WGPU_EXPECT_RESOLVEVIEW_NOTSET); + #elif defined(_SOKOL_ANY_GL) + _SG_VALIDATE(pass->swapchain.gl.framebuffer == 0, VALIDATE_BEGINPASS_SWAPCHAIN_GL_EXPECT_FRAMEBUFFER_NOTSET); + #endif } return _sg_validate_end(); #endif @@ -16252,16 +16147,20 @@ _SOKOL_PRIVATE bool _sg_validate_apply_pipeline(sg_pipeline pip_id) { _SG_VALIDATE(pip->shader->slot.id == pip->cmn.shader_id.id, VALIDATE_APIP_SHADER_EXISTS); _SG_VALIDATE(pip->shader->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_APIP_SHADER_VALID); // check that pipeline attributes match current pass attributes - const _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, _sg.cur_pass.id); - if (pass) { + if (_sg.cur_pass.atts_id.id != SG_INVALID_ID) { // an offscreen pass - _SG_VALIDATE(pip->cmn.color_count == pass->cmn.num_color_atts, VALIDATE_APIP_ATT_COUNT); + const _sg_attachments_t* atts = _sg.cur_pass.atts; + SOKOL_ASSERT(atts); + _SG_VALIDATE(atts->slot.id == _sg.cur_pass.atts_id.id, VALIDATE_APIP_CURPASS_ATTACHMENTS_EXISTS); + _SG_VALIDATE(atts->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_APIP_CURPASS_ATTACHMENTS_VALID); + + _SG_VALIDATE(pip->cmn.color_count == atts->cmn.num_colors, VALIDATE_APIP_ATT_COUNT); for (int i = 0; i < pip->cmn.color_count; i++) { - const _sg_image_t* att_img = _sg_pass_color_image(pass, i); + const _sg_image_t* att_img = _sg_attachments_color_image(atts, i); _SG_VALIDATE(pip->cmn.colors[i].pixel_format == att_img->cmn.pixel_format, VALIDATE_APIP_COLOR_FORMAT); _SG_VALIDATE(pip->cmn.sample_count == att_img->cmn.sample_count, VALIDATE_APIP_SAMPLE_COUNT); } - const _sg_image_t* att_dsimg = _sg_pass_ds_image(pass); + const _sg_image_t* att_dsimg = _sg_attachments_ds_image(atts); if (att_dsimg) { _SG_VALIDATE(pip->cmn.depth.pixel_format == att_dsimg->cmn.pixel_format, VALIDATE_APIP_DEPTH_FORMAT); } else { @@ -16270,9 +16169,9 @@ _SOKOL_PRIVATE bool _sg_validate_apply_pipeline(sg_pipeline pip_id) { } else { // default pass _SG_VALIDATE(pip->cmn.color_count == 1, VALIDATE_APIP_ATT_COUNT); - _SG_VALIDATE(pip->cmn.colors[0].pixel_format == _sg.desc.context.color_format, VALIDATE_APIP_COLOR_FORMAT); - _SG_VALIDATE(pip->cmn.depth.pixel_format == _sg.desc.context.depth_format, VALIDATE_APIP_DEPTH_FORMAT); - _SG_VALIDATE(pip->cmn.sample_count == _sg.desc.context.sample_count, VALIDATE_APIP_SAMPLE_COUNT); + _SG_VALIDATE(pip->cmn.colors[0].pixel_format == _sg.cur_pass.swapchain.color_fmt, VALIDATE_APIP_COLOR_FORMAT); + _SG_VALIDATE(pip->cmn.depth.pixel_format == _sg.cur_pass.swapchain.depth_fmt, VALIDATE_APIP_DEPTH_FORMAT); + _SG_VALIDATE(pip->cmn.sample_count == _sg.cur_pass.swapchain.sample_count, VALIDATE_APIP_SAMPLE_COUNT); } return _sg_validate_end(); #endif @@ -16564,8 +16463,8 @@ _SOKOL_PRIVATE sg_image_desc _sg_image_desc_defaults(const sg_image_desc* desc) def.num_mipmaps = _sg_def(def.num_mipmaps, 1); def.usage = _sg_def(def.usage, SG_USAGE_IMMUTABLE); if (desc->render_target) { - def.pixel_format = _sg_def(def.pixel_format, _sg.desc.context.color_format); - def.sample_count = _sg_def(def.sample_count, _sg.desc.context.sample_count); + def.pixel_format = _sg_def(def.pixel_format, _sg.desc.environment.defaults.color_format); + def.sample_count = _sg_def(def.sample_count, _sg.desc.environment.defaults.sample_count); } else { def.pixel_format = _sg_def(def.pixel_format, SG_PIXELFORMAT_RGBA8); def.sample_count = _sg_def(def.sample_count, 1); @@ -16647,7 +16546,7 @@ _SOKOL_PRIVATE sg_pipeline_desc _sg_pipeline_desc_defaults(const sg_pipeline_des def.index_type = _sg_def(def.index_type, SG_INDEXTYPE_NONE); def.cull_mode = _sg_def(def.cull_mode, SG_CULLMODE_NONE); def.face_winding = _sg_def(def.face_winding, SG_FACEWINDING_CW); - def.sample_count = _sg_def(def.sample_count, _sg.desc.context.sample_count); + def.sample_count = _sg_def(def.sample_count, _sg.desc.environment.defaults.sample_count); def.stencil.front.compare = _sg_def(def.stencil.front.compare, SG_COMPAREFUNC_ALWAYS); def.stencil.front.fail_op = _sg_def(def.stencil.front.fail_op, SG_STENCILOP_KEEP); @@ -16659,7 +16558,7 @@ _SOKOL_PRIVATE sg_pipeline_desc _sg_pipeline_desc_defaults(const sg_pipeline_des def.stencil.back.pass_op = _sg_def(def.stencil.back.pass_op, SG_STENCILOP_KEEP); def.depth.compare = _sg_def(def.depth.compare, SG_COMPAREFUNC_ALWAYS); - def.depth.pixel_format = _sg_def(def.depth.pixel_format, _sg.desc.context.depth_format); + def.depth.pixel_format = _sg_def(def.depth.pixel_format, _sg.desc.environment.defaults.depth_format); if (def.colors[0].pixel_format == SG_PIXELFORMAT_NONE) { // special case depth-only rendering, enforce a color count of 0 def.color_count = 0; @@ -16671,7 +16570,7 @@ _SOKOL_PRIVATE sg_pipeline_desc _sg_pipeline_desc_defaults(const sg_pipeline_des } for (int i = 0; i < def.color_count; i++) { sg_color_target_state* cs = &def.colors[i]; - cs->pixel_format = _sg_def(cs->pixel_format, _sg.desc.context.color_format); + cs->pixel_format = _sg_def(cs->pixel_format, _sg.desc.environment.defaults.color_format); cs->write_mask = _sg_def(cs->write_mask, SG_COLORMASK_RGBA); sg_blend_state* bs = &def.colors[i].blend; bs->src_factor_rgb = _sg_def(bs->src_factor_rgb, SG_BLENDFACTOR_ONE); @@ -16725,9 +16624,8 @@ _SOKOL_PRIVATE sg_pipeline_desc _sg_pipeline_desc_defaults(const sg_pipeline_des return def; } -_SOKOL_PRIVATE sg_pass_desc _sg_pass_desc_defaults(const sg_pass_desc* desc) { - // FIXME: no values to replace in sg_pass_desc? - sg_pass_desc def = *desc; +_SOKOL_PRIVATE sg_attachments_desc _sg_attachments_desc_defaults(const sg_attachments_desc* desc) { + sg_attachments_desc def = *desc; return def; } @@ -16791,11 +16689,11 @@ _SOKOL_PRIVATE sg_pipeline _sg_alloc_pipeline(void) { return res; } -_SOKOL_PRIVATE sg_pass _sg_alloc_pass(void) { - sg_pass res; - int slot_index = _sg_pool_alloc_index(&_sg.pools.pass_pool); +_SOKOL_PRIVATE sg_attachments _sg_alloc_attachments(void) { + sg_attachments res; + int slot_index = _sg_pool_alloc_index(&_sg.pools.attachments_pool); if (_SG_INVALID_SLOT_INDEX != slot_index) { - res.id = _sg_slot_alloc(&_sg.pools.pass_pool, &_sg.pools.passes[slot_index].slot, slot_index); + res.id = _sg_slot_alloc(&_sg.pools.attachments_pool, &_sg.pools.attachments[slot_index].slot, slot_index); } else { res.id = SG_INVALID_ID; _SG_ERROR(PASS_POOL_EXHAUSTED); @@ -16833,16 +16731,15 @@ _SOKOL_PRIVATE void _sg_dealloc_pipeline(_sg_pipeline_t* pip) { _sg_reset_slot(&pip->slot); } -_SOKOL_PRIVATE void _sg_dealloc_pass(_sg_pass_t* pass) { - SOKOL_ASSERT(pass && (pass->slot.state == SG_RESOURCESTATE_ALLOC) && (pass->slot.id != SG_INVALID_ID)); - _sg_pool_free_index(&_sg.pools.pass_pool, _sg_slot_index(pass->slot.id)); - _sg_reset_slot(&pass->slot); +_SOKOL_PRIVATE void _sg_dealloc_attachments(_sg_attachments_t* atts) { + SOKOL_ASSERT(atts && (atts->slot.state == SG_RESOURCESTATE_ALLOC) && (atts->slot.id != SG_INVALID_ID)); + _sg_pool_free_index(&_sg.pools.attachments_pool, _sg_slot_index(atts->slot.id)); + _sg_reset_slot(&atts->slot); } _SOKOL_PRIVATE void _sg_init_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { SOKOL_ASSERT(buf && (buf->slot.state == SG_RESOURCESTATE_ALLOC)); SOKOL_ASSERT(desc); - buf->slot.ctx_id = _sg.active_context.id; if (_sg_validate_buffer_desc(desc)) { _sg_buffer_common_init(&buf->cmn, desc); buf->slot.state = _sg_create_buffer(buf, desc); @@ -16855,7 +16752,6 @@ _SOKOL_PRIVATE void _sg_init_buffer(_sg_buffer_t* buf, const sg_buffer_desc* des _SOKOL_PRIVATE void _sg_init_image(_sg_image_t* img, const sg_image_desc* desc) { SOKOL_ASSERT(img && (img->slot.state == SG_RESOURCESTATE_ALLOC)); SOKOL_ASSERT(desc); - img->slot.ctx_id = _sg.active_context.id; if (_sg_validate_image_desc(desc)) { _sg_image_common_init(&img->cmn, desc); img->slot.state = _sg_create_image(img, desc); @@ -16868,7 +16764,6 @@ _SOKOL_PRIVATE void _sg_init_image(_sg_image_t* img, const sg_image_desc* desc) _SOKOL_PRIVATE void _sg_init_sampler(_sg_sampler_t* smp, const sg_sampler_desc* desc) { SOKOL_ASSERT(smp && (smp->slot.state == SG_RESOURCESTATE_ALLOC)); SOKOL_ASSERT(desc); - smp->slot.ctx_id = _sg.active_context.id; if (_sg_validate_sampler_desc(desc)) { _sg_sampler_common_init(&smp->cmn, desc); smp->slot.state = _sg_create_sampler(smp, desc); @@ -16881,7 +16776,6 @@ _SOKOL_PRIVATE void _sg_init_sampler(_sg_sampler_t* smp, const sg_sampler_desc* _SOKOL_PRIVATE void _sg_init_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { SOKOL_ASSERT(shd && (shd->slot.state == SG_RESOURCESTATE_ALLOC)); SOKOL_ASSERT(desc); - shd->slot.ctx_id = _sg.active_context.id; if (_sg_validate_shader_desc(desc)) { _sg_shader_common_init(&shd->cmn, desc); shd->slot.state = _sg_create_shader(shd, desc); @@ -16894,7 +16788,6 @@ _SOKOL_PRIVATE void _sg_init_shader(_sg_shader_t* shd, const sg_shader_desc* des _SOKOL_PRIVATE void _sg_init_pipeline(_sg_pipeline_t* pip, const sg_pipeline_desc* desc) { SOKOL_ASSERT(pip && (pip->slot.state == SG_RESOURCESTATE_ALLOC)); SOKOL_ASSERT(desc); - pip->slot.ctx_id = _sg.active_context.id; if (_sg_validate_pipeline_desc(desc)) { _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, desc->shader.id); if (shd && (shd->slot.state == SG_RESOURCESTATE_VALID)) { @@ -16909,11 +16802,10 @@ _SOKOL_PRIVATE void _sg_init_pipeline(_sg_pipeline_t* pip, const sg_pipeline_des SOKOL_ASSERT((pip->slot.state == SG_RESOURCESTATE_VALID)||(pip->slot.state == SG_RESOURCESTATE_FAILED)); } -_SOKOL_PRIVATE void _sg_init_pass(_sg_pass_t* pass, const sg_pass_desc* desc) { - SOKOL_ASSERT(pass && pass->slot.state == SG_RESOURCESTATE_ALLOC); +_SOKOL_PRIVATE void _sg_init_attachments(_sg_attachments_t* atts, const sg_attachments_desc* desc) { + SOKOL_ASSERT(atts && atts->slot.state == SG_RESOURCESTATE_ALLOC); SOKOL_ASSERT(desc); - pass->slot.ctx_id = _sg.active_context.id; - if (_sg_validate_pass_desc(desc)) { + if (_sg_validate_attachments_desc(desc)) { // lookup pass attachment image pointers _sg_image_t* color_images[SG_MAX_COLOR_ATTACHMENTS] = { 0 }; _sg_image_t* resolve_images[SG_MAX_COLOR_ATTACHMENTS] = { 0 }; @@ -16922,100 +16814,76 @@ _SOKOL_PRIVATE void _sg_init_pass(_sg_pass_t* pass, const sg_pass_desc* desc) { int width = 0; int height = 0; for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - if (desc->color_attachments[i].image.id) { - color_images[i] = _sg_lookup_image(&_sg.pools, desc->color_attachments[i].image.id); + if (desc->colors[i].image.id) { + color_images[i] = _sg_lookup_image(&_sg.pools, desc->colors[i].image.id); if (!(color_images[i] && color_images[i]->slot.state == SG_RESOURCESTATE_VALID)) { - pass->slot.state = SG_RESOURCESTATE_FAILED; + atts->slot.state = SG_RESOURCESTATE_FAILED; return; } - const int mip_level = desc->color_attachments[i].mip_level; + const int mip_level = desc->colors[i].mip_level; width = _sg_miplevel_dim(color_images[i]->cmn.width, mip_level); height = _sg_miplevel_dim(color_images[i]->cmn.height, mip_level); } - if (desc->resolve_attachments[i].image.id) { - resolve_images[i] = _sg_lookup_image(&_sg.pools, desc->resolve_attachments[i].image.id); + if (desc->resolves[i].image.id) { + resolve_images[i] = _sg_lookup_image(&_sg.pools, desc->resolves[i].image.id); if (!(resolve_images[i] && resolve_images[i]->slot.state == SG_RESOURCESTATE_VALID)) { - pass->slot.state = SG_RESOURCESTATE_FAILED; + atts->slot.state = SG_RESOURCESTATE_FAILED; return; } } } - if (desc->depth_stencil_attachment.image.id) { - ds_image = _sg_lookup_image(&_sg.pools, desc->depth_stencil_attachment.image.id); + if (desc->depth_stencil.image.id) { + ds_image = _sg_lookup_image(&_sg.pools, desc->depth_stencil.image.id); if (!(ds_image && ds_image->slot.state == SG_RESOURCESTATE_VALID)) { - pass->slot.state = SG_RESOURCESTATE_FAILED; + atts->slot.state = SG_RESOURCESTATE_FAILED; return; } - const int mip_level = desc->depth_stencil_attachment.mip_level; + const int mip_level = desc->depth_stencil.mip_level; width = _sg_miplevel_dim(ds_image->cmn.width, mip_level); height = _sg_miplevel_dim(ds_image->cmn.height, mip_level); } - _sg_pass_common_init(&pass->cmn, desc, width, height); - pass->slot.state = _sg_create_pass(pass, color_images, resolve_images, ds_image, desc); + _sg_attachments_common_init(&atts->cmn, desc, width, height); + atts->slot.state = _sg_create_attachments(atts, color_images, resolve_images, ds_image, desc); } else { - pass->slot.state = SG_RESOURCESTATE_FAILED; + atts->slot.state = SG_RESOURCESTATE_FAILED; } - SOKOL_ASSERT((pass->slot.state == SG_RESOURCESTATE_VALID)||(pass->slot.state == SG_RESOURCESTATE_FAILED)); + SOKOL_ASSERT((atts->slot.state == SG_RESOURCESTATE_VALID)||(atts->slot.state == SG_RESOURCESTATE_FAILED)); } _SOKOL_PRIVATE void _sg_uninit_buffer(_sg_buffer_t* buf) { SOKOL_ASSERT(buf && ((buf->slot.state == SG_RESOURCESTATE_VALID) || (buf->slot.state == SG_RESOURCESTATE_FAILED))); - if (buf->slot.ctx_id == _sg.active_context.id) { - _sg_discard_buffer(buf); - _sg_reset_buffer_to_alloc_state(buf); - } else { - _SG_WARN(UNINIT_BUFFER_ACTIVE_CONTEXT_MISMATCH); - } + _sg_discard_buffer(buf); + _sg_reset_buffer_to_alloc_state(buf); } _SOKOL_PRIVATE void _sg_uninit_image(_sg_image_t* img) { SOKOL_ASSERT(img && ((img->slot.state == SG_RESOURCESTATE_VALID) || (img->slot.state == SG_RESOURCESTATE_FAILED))); - if (img->slot.ctx_id == _sg.active_context.id) { - _sg_discard_image(img); - _sg_reset_image_to_alloc_state(img); - } else { - _SG_WARN(UNINIT_IMAGE_ACTIVE_CONTEXT_MISMATCH); - } + _sg_discard_image(img); + _sg_reset_image_to_alloc_state(img); } _SOKOL_PRIVATE void _sg_uninit_sampler(_sg_sampler_t* smp) { SOKOL_ASSERT(smp && ((smp->slot.state == SG_RESOURCESTATE_VALID) || (smp->slot.state == SG_RESOURCESTATE_FAILED))); - if (smp->slot.ctx_id == _sg.active_context.id) { - _sg_discard_sampler(smp); - _sg_reset_sampler_to_alloc_state(smp); - } else { - _SG_WARN(UNINIT_SAMPLER_ACTIVE_CONTEXT_MISMATCH); - } + _sg_discard_sampler(smp); + _sg_reset_sampler_to_alloc_state(smp); } _SOKOL_PRIVATE void _sg_uninit_shader(_sg_shader_t* shd) { SOKOL_ASSERT(shd && ((shd->slot.state == SG_RESOURCESTATE_VALID) || (shd->slot.state == SG_RESOURCESTATE_FAILED))); - if (shd->slot.ctx_id == _sg.active_context.id) { - _sg_discard_shader(shd); - _sg_reset_shader_to_alloc_state(shd); - } else { - _SG_WARN(UNINIT_SHADER_ACTIVE_CONTEXT_MISMATCH); - } + _sg_discard_shader(shd); + _sg_reset_shader_to_alloc_state(shd); } _SOKOL_PRIVATE void _sg_uninit_pipeline(_sg_pipeline_t* pip) { SOKOL_ASSERT(pip && ((pip->slot.state == SG_RESOURCESTATE_VALID) || (pip->slot.state == SG_RESOURCESTATE_FAILED))); - if (pip->slot.ctx_id == _sg.active_context.id) { - _sg_discard_pipeline(pip); - _sg_reset_pipeline_to_alloc_state(pip); - } else { - _SG_WARN(UNINIT_PIPELINE_ACTIVE_CONTEXT_MISMATCH); - } + _sg_discard_pipeline(pip); + _sg_reset_pipeline_to_alloc_state(pip); } -_SOKOL_PRIVATE void _sg_uninit_pass(_sg_pass_t* pass) { - SOKOL_ASSERT(pass && ((pass->slot.state == SG_RESOURCESTATE_VALID) || (pass->slot.state == SG_RESOURCESTATE_FAILED))); - if (pass->slot.ctx_id == _sg.active_context.id) { - _sg_discard_pass(pass); - _sg_reset_pass_to_alloc_state(pass); - } else { - _SG_WARN(UNINIT_PASS_ACTIVE_CONTEXT_MISMATCH); - } +_SOKOL_PRIVATE void _sg_uninit_attachments(_sg_attachments_t* atts) { + SOKOL_ASSERT(atts && ((atts->slot.state == SG_RESOURCESTATE_VALID) || (atts->slot.state == SG_RESOURCESTATE_FAILED))); + _sg_discard_attachments(atts); + _sg_reset_attachments_to_alloc_state(atts); } _SOKOL_PRIVATE void _sg_setup_commit_listeners(const sg_desc* desc) { @@ -17101,27 +16969,38 @@ _SOKOL_PRIVATE sg_desc _sg_desc_defaults(const sg_desc* desc) { */ sg_desc res = *desc; #if defined(SOKOL_WGPU) - SOKOL_ASSERT(SG_PIXELFORMAT_NONE != res.context.color_format); + SOKOL_ASSERT(SG_PIXELFORMAT_NONE < res.environment.defaults.color_format); #elif defined(SOKOL_METAL) || defined(SOKOL_D3D11) - res.context.color_format = _sg_def(res.context.color_format, SG_PIXELFORMAT_BGRA8); + res.environment.defaults.color_format = _sg_def(res.environment.defaults.color_format, SG_PIXELFORMAT_BGRA8); #else - res.context.color_format = _sg_def(res.context.color_format, SG_PIXELFORMAT_RGBA8); + res.environment.defaults.color_format = _sg_def(res.environment.defaults.color_format, SG_PIXELFORMAT_RGBA8); #endif - res.context.depth_format = _sg_def(res.context.depth_format, SG_PIXELFORMAT_DEPTH_STENCIL); - res.context.sample_count = _sg_def(res.context.sample_count, 1); + res.environment.defaults.depth_format = _sg_def(res.environment.defaults.depth_format, SG_PIXELFORMAT_DEPTH_STENCIL); + res.environment.defaults.sample_count = _sg_def(res.environment.defaults.sample_count, 1); res.buffer_pool_size = _sg_def(res.buffer_pool_size, _SG_DEFAULT_BUFFER_POOL_SIZE); res.image_pool_size = _sg_def(res.image_pool_size, _SG_DEFAULT_IMAGE_POOL_SIZE); res.sampler_pool_size = _sg_def(res.sampler_pool_size, _SG_DEFAULT_SAMPLER_POOL_SIZE); res.shader_pool_size = _sg_def(res.shader_pool_size, _SG_DEFAULT_SHADER_POOL_SIZE); res.pipeline_pool_size = _sg_def(res.pipeline_pool_size, _SG_DEFAULT_PIPELINE_POOL_SIZE); - res.pass_pool_size = _sg_def(res.pass_pool_size, _SG_DEFAULT_PASS_POOL_SIZE); - res.context_pool_size = _sg_def(res.context_pool_size, _SG_DEFAULT_CONTEXT_POOL_SIZE); + res.attachments_pool_size = _sg_def(res.attachments_pool_size, _SG_DEFAULT_ATTACHMENTS_POOL_SIZE); res.uniform_buffer_size = _sg_def(res.uniform_buffer_size, _SG_DEFAULT_UB_SIZE); res.max_commit_listeners = _sg_def(res.max_commit_listeners, _SG_DEFAULT_MAX_COMMIT_LISTENERS); res.wgpu_bindgroups_cache_size = _sg_def(res.wgpu_bindgroups_cache_size, _SG_DEFAULT_WGPU_BINDGROUP_CACHE_SIZE); return res; } +_SOKOL_PRIVATE sg_pass _sg_pass_defaults(const sg_pass* pass) { + sg_pass res = *pass; + if (res.attachments.id == SG_INVALID_ID) { + // this is a swapchain-pass + res.swapchain.sample_count = _sg_def(res.swapchain.sample_count, _sg.desc.environment.defaults.sample_count); + res.swapchain.color_format = _sg_def(res.swapchain.color_format, _sg.desc.environment.defaults.color_format); + res.swapchain.depth_format = _sg_def(res.swapchain.depth_format, _sg.desc.environment.defaults.depth_format); + } + res.action = _sg_pass_action_defaults(&res.action); + return res; +} + // ██████ ██ ██ ██████ ██ ██ ██████ // ██ ██ ██ ██ ██ ██ ██ ██ ██ // ██████ ██ ██ ██████ ██ ██ ██ @@ -17141,21 +17020,10 @@ SOKOL_API_IMPL void sg_setup(const sg_desc* desc) { _sg.stats_enabled = true; _sg_setup_backend(&_sg.desc); _sg.valid = true; - sg_setup_context(); } SOKOL_API_IMPL void sg_shutdown(void) { - /* can only delete resources for the currently set context here, if multiple - contexts are used, the app code must take care of properly releasing them - (since only the app code can switch between 3D-API contexts) - */ - if (_sg.active_context.id != SG_INVALID_ID) { - _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, _sg.active_context.id); - if (ctx) { - _sg_discard_all_resources(&_sg.pools, _sg.active_context.id); - _sg_discard_context(ctx); - } - } + _sg_discard_all_resources(&_sg.pools); _sg_discard_backend(); _sg_discard_commit_listeners(); _sg_discard_pools(&_sg.pools); @@ -17227,46 +17095,6 @@ SOKOL_API_IMPL sg_frame_stats sg_query_frame_stats(void) { return _sg.prev_stats; } -SOKOL_API_IMPL sg_context sg_setup_context(void) { - SOKOL_ASSERT(_sg.valid); - sg_context res; - int slot_index = _sg_pool_alloc_index(&_sg.pools.context_pool); - if (_SG_INVALID_SLOT_INDEX != slot_index) { - res.id = _sg_slot_alloc(&_sg.pools.context_pool, &_sg.pools.contexts[slot_index].slot, slot_index); - _sg_context_t* ctx = _sg_context_at(&_sg.pools, res.id); - ctx->slot.state = _sg_create_context(ctx); - SOKOL_ASSERT(ctx->slot.state == SG_RESOURCESTATE_VALID); - _sg_activate_context(ctx); - } else { - // pool is exhausted - res.id = SG_INVALID_ID; - } - _sg.active_context = res; - return res; -} - -SOKOL_API_IMPL void sg_discard_context(sg_context ctx_id) { - SOKOL_ASSERT(_sg.valid); - _sg_discard_all_resources(&_sg.pools, ctx_id.id); - _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, ctx_id.id); - if (ctx) { - _sg_discard_context(ctx); - _sg_reset_context_to_alloc_state(ctx); - _sg_reset_slot(&ctx->slot); - _sg_pool_free_index(&_sg.pools.context_pool, _sg_slot_index(ctx_id.id)); - } - _sg.active_context.id = SG_INVALID_ID; - _sg_activate_context(0); -} - -SOKOL_API_IMPL void sg_activate_context(sg_context ctx_id) { - SOKOL_ASSERT(_sg.valid); - _sg.active_context = ctx_id; - _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, ctx_id.id); - // NOTE: ctx can be 0 here if the context is no longer valid - _sg_activate_context(ctx); -} - SOKOL_API_IMPL sg_trace_hooks sg_install_trace_hooks(const sg_trace_hooks* trace_hooks) { SOKOL_ASSERT(_sg.valid); SOKOL_ASSERT(trace_hooks); @@ -17316,10 +17144,10 @@ SOKOL_API_IMPL sg_pipeline sg_alloc_pipeline(void) { return res; } -SOKOL_API_IMPL sg_pass sg_alloc_pass(void) { +SOKOL_API_IMPL sg_attachments sg_alloc_attachments(void) { SOKOL_ASSERT(_sg.valid); - sg_pass res = _sg_alloc_pass(); - _SG_TRACE_ARGS(alloc_pass, res); + sg_attachments res = _sg_alloc_attachments(); + _SG_TRACE_ARGS(alloc_attachments, res); return res; } @@ -17388,17 +17216,17 @@ SOKOL_API_IMPL void sg_dealloc_pipeline(sg_pipeline pip_id) { _SG_TRACE_ARGS(dealloc_pipeline, pip_id); } -SOKOL_API_IMPL void sg_dealloc_pass(sg_pass pass_id) { +SOKOL_API_IMPL void sg_dealloc_attachments(sg_attachments atts_id) { SOKOL_ASSERT(_sg.valid); - _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass) { - if (pass->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_pass(pass); + _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); + if (atts) { + if (atts->slot.state == SG_RESOURCESTATE_ALLOC) { + _sg_dealloc_attachments(atts); } else { - _SG_ERROR(DEALLOC_PASS_INVALID_STATE); + _SG_ERROR(DEALLOC_ATTACHMENTS_INVALID_STATE); } } - _SG_TRACE_ARGS(dealloc_pass, pass_id); + _SG_TRACE_ARGS(dealloc_attachments, atts_id); } SOKOL_API_IMPL void sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc) { @@ -17476,19 +17304,19 @@ SOKOL_API_IMPL void sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc* _SG_TRACE_ARGS(init_pipeline, pip_id, &desc_def); } -SOKOL_API_IMPL void sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc) { +SOKOL_API_IMPL void sg_init_attachments(sg_attachments atts_id, const sg_attachments_desc* desc) { SOKOL_ASSERT(_sg.valid); - sg_pass_desc desc_def = _sg_pass_desc_defaults(desc); - _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass) { - if (pass->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_init_pass(pass, &desc_def); - SOKOL_ASSERT((pass->slot.state == SG_RESOURCESTATE_VALID) || (pass->slot.state == SG_RESOURCESTATE_FAILED)); + sg_attachments_desc desc_def = _sg_attachments_desc_defaults(desc); + _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); + if (atts) { + if (atts->slot.state == SG_RESOURCESTATE_ALLOC) { + _sg_init_attachments(atts, &desc_def); + SOKOL_ASSERT((atts->slot.state == SG_RESOURCESTATE_VALID) || (atts->slot.state == SG_RESOURCESTATE_FAILED)); } else { - _SG_ERROR(INIT_PASS_INVALID_STATE); + _SG_ERROR(INIT_ATTACHMENTS_INVALID_STATE); } } - _SG_TRACE_ARGS(init_pass, pass_id, &desc_def); + _SG_TRACE_ARGS(init_attachments, atts_id, &desc_def); } SOKOL_API_IMPL void sg_uninit_buffer(sg_buffer buf_id) { @@ -17561,18 +17389,18 @@ SOKOL_API_IMPL void sg_uninit_pipeline(sg_pipeline pip_id) { _SG_TRACE_ARGS(uninit_pipeline, pip_id); } -SOKOL_API_IMPL void sg_uninit_pass(sg_pass pass_id) { +SOKOL_API_IMPL void sg_uninit_attachments(sg_attachments atts_id) { SOKOL_ASSERT(_sg.valid); - _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass) { - if ((pass->slot.state == SG_RESOURCESTATE_VALID) || (pass->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_pass(pass); - SOKOL_ASSERT(pass->slot.state == SG_RESOURCESTATE_ALLOC); + _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); + if (atts) { + if ((atts->slot.state == SG_RESOURCESTATE_VALID) || (atts->slot.state == SG_RESOURCESTATE_FAILED)) { + _sg_uninit_attachments(atts); + SOKOL_ASSERT(atts->slot.state == SG_RESOURCESTATE_ALLOC); } else { - _SG_ERROR(UNINIT_PASS_INVALID_STATE); + _SG_ERROR(UNINIT_ATTACHMENTS_INVALID_STATE); } } - _SG_TRACE_ARGS(uninit_pass, pass_id); + _SG_TRACE_ARGS(uninit_attachments, atts_id); } SOKOL_API_IMPL void sg_fail_buffer(sg_buffer buf_id) { @@ -17580,7 +17408,6 @@ SOKOL_API_IMPL void sg_fail_buffer(sg_buffer buf_id) { _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); if (buf) { if (buf->slot.state == SG_RESOURCESTATE_ALLOC) { - buf->slot.ctx_id = _sg.active_context.id; buf->slot.state = SG_RESOURCESTATE_FAILED; } else { _SG_ERROR(FAIL_BUFFER_INVALID_STATE); @@ -17594,7 +17421,6 @@ SOKOL_API_IMPL void sg_fail_image(sg_image img_id) { _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); if (img) { if (img->slot.state == SG_RESOURCESTATE_ALLOC) { - img->slot.ctx_id = _sg.active_context.id; img->slot.state = SG_RESOURCESTATE_FAILED; } else { _SG_ERROR(FAIL_IMAGE_INVALID_STATE); @@ -17608,7 +17434,6 @@ SOKOL_API_IMPL void sg_fail_sampler(sg_sampler smp_id) { _sg_sampler_t* smp = _sg_lookup_sampler(&_sg.pools, smp_id.id); if (smp) { if (smp->slot.state == SG_RESOURCESTATE_ALLOC) { - smp->slot.ctx_id = _sg.active_context.id; smp->slot.state = SG_RESOURCESTATE_FAILED; } else { _SG_ERROR(FAIL_SAMPLER_INVALID_STATE); @@ -17622,7 +17447,6 @@ SOKOL_API_IMPL void sg_fail_shader(sg_shader shd_id) { _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); if (shd) { if (shd->slot.state == SG_RESOURCESTATE_ALLOC) { - shd->slot.ctx_id = _sg.active_context.id; shd->slot.state = SG_RESOURCESTATE_FAILED; } else { _SG_ERROR(FAIL_SHADER_INVALID_STATE); @@ -17636,7 +17460,6 @@ SOKOL_API_IMPL void sg_fail_pipeline(sg_pipeline pip_id) { _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); if (pip) { if (pip->slot.state == SG_RESOURCESTATE_ALLOC) { - pip->slot.ctx_id = _sg.active_context.id; pip->slot.state = SG_RESOURCESTATE_FAILED; } else { _SG_ERROR(FAIL_PIPELINE_INVALID_STATE); @@ -17645,18 +17468,17 @@ SOKOL_API_IMPL void sg_fail_pipeline(sg_pipeline pip_id) { _SG_TRACE_ARGS(fail_pipeline, pip_id); } -SOKOL_API_IMPL void sg_fail_pass(sg_pass pass_id) { +SOKOL_API_IMPL void sg_fail_attachments(sg_attachments atts_id) { SOKOL_ASSERT(_sg.valid); - _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass) { - if (pass->slot.state == SG_RESOURCESTATE_ALLOC) { - pass->slot.ctx_id = _sg.active_context.id; - pass->slot.state = SG_RESOURCESTATE_FAILED; + _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); + if (atts) { + if (atts->slot.state == SG_RESOURCESTATE_ALLOC) { + atts->slot.state = SG_RESOURCESTATE_FAILED; } else { - _SG_ERROR(FAIL_PASS_INVALID_STATE); + _SG_ERROR(FAIL_ATTACHMENTS_INVALID_STATE); } } - _SG_TRACE_ARGS(fail_pass, pass_id); + _SG_TRACE_ARGS(fail_attachments, atts_id); } SOKOL_API_IMPL sg_resource_state sg_query_buffer_state(sg_buffer buf_id) { @@ -17694,10 +17516,10 @@ SOKOL_API_IMPL sg_resource_state sg_query_pipeline_state(sg_pipeline pip_id) { return res; } -SOKOL_API_IMPL sg_resource_state sg_query_pass_state(sg_pass pass_id) { +SOKOL_API_IMPL sg_resource_state sg_query_attachments_state(sg_attachments atts_id) { SOKOL_ASSERT(_sg.valid); - _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - sg_resource_state res = pass ? pass->slot.state : SG_RESOURCESTATE_INVALID; + _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); + sg_resource_state res = atts ? atts->slot.state : SG_RESOURCESTATE_INVALID; return res; } @@ -17776,19 +17598,19 @@ SOKOL_API_IMPL sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc) { return pip_id; } -SOKOL_API_IMPL sg_pass sg_make_pass(const sg_pass_desc* desc) { +SOKOL_API_IMPL sg_attachments sg_make_attachments(const sg_attachments_desc* desc) { SOKOL_ASSERT(_sg.valid); SOKOL_ASSERT(desc); - sg_pass_desc desc_def = _sg_pass_desc_defaults(desc); - sg_pass pass_id = _sg_alloc_pass(); - if (pass_id.id != SG_INVALID_ID) { - _sg_pass_t* pass = _sg_pass_at(&_sg.pools, pass_id.id); - SOKOL_ASSERT(pass && (pass->slot.state == SG_RESOURCESTATE_ALLOC)); - _sg_init_pass(pass, &desc_def); - SOKOL_ASSERT((pass->slot.state == SG_RESOURCESTATE_VALID) || (pass->slot.state == SG_RESOURCESTATE_FAILED)); + sg_attachments_desc desc_def = _sg_attachments_desc_defaults(desc); + sg_attachments atts_id = _sg_alloc_attachments(); + if (atts_id.id != SG_INVALID_ID) { + _sg_attachments_t* atts = _sg_attachments_at(&_sg.pools, atts_id.id); + SOKOL_ASSERT(atts && (atts->slot.state == SG_RESOURCESTATE_ALLOC)); + _sg_init_attachments(atts, &desc_def); + SOKOL_ASSERT((atts->slot.state == SG_RESOURCESTATE_VALID) || (atts->slot.state == SG_RESOURCESTATE_FAILED)); } - _SG_TRACE_ARGS(make_pass, &desc_def, pass_id); - return pass_id; + _SG_TRACE_ARGS(make_attachments, &desc_def, atts_id); + return atts_id; } SOKOL_API_IMPL void sg_destroy_buffer(sg_buffer buf_id) { @@ -17871,59 +17693,66 @@ SOKOL_API_IMPL void sg_destroy_pipeline(sg_pipeline pip_id) { } } -SOKOL_API_IMPL void sg_destroy_pass(sg_pass pass_id) { +SOKOL_API_IMPL void sg_destroy_attachments(sg_attachments atts_id) { SOKOL_ASSERT(_sg.valid); - _SG_TRACE_ARGS(destroy_pass, pass_id); - _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass) { - if ((pass->slot.state == SG_RESOURCESTATE_VALID) || (pass->slot.state == SG_RESOURCESTATE_FAILED)) { - _sg_uninit_pass(pass); - SOKOL_ASSERT(pass->slot.state == SG_RESOURCESTATE_ALLOC); + _SG_TRACE_ARGS(destroy_attachments, atts_id); + _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); + if (atts) { + if ((atts->slot.state == SG_RESOURCESTATE_VALID) || (atts->slot.state == SG_RESOURCESTATE_FAILED)) { + _sg_uninit_attachments(atts); + SOKOL_ASSERT(atts->slot.state == SG_RESOURCESTATE_ALLOC); } - if (pass->slot.state == SG_RESOURCESTATE_ALLOC) { - _sg_dealloc_pass(pass); - SOKOL_ASSERT(pass->slot.state == SG_RESOURCESTATE_INITIAL); + if (atts->slot.state == SG_RESOURCESTATE_ALLOC) { + _sg_dealloc_attachments(atts); + SOKOL_ASSERT(atts->slot.state == SG_RESOURCESTATE_INITIAL); } } } -SOKOL_API_IMPL void sg_begin_default_pass(const sg_pass_action* pass_action, int width, int height) { +SOKOL_API_IMPL void sg_begin_pass(const sg_pass* pass) { SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(pass_action); - SOKOL_ASSERT((pass_action->_start_canary == 0) && (pass_action->_end_canary == 0)); - sg_pass_action pa; - _sg_resolve_default_pass_action(pass_action, &pa); - _sg.cur_pass.id = SG_INVALID_ID; - _sg.pass_valid = true; - _sg_begin_pass(0, &pa, width, height); - _SG_TRACE_ARGS(begin_default_pass, &pa, width, height); -} - -SOKOL_API_IMPL void sg_begin_default_passf(const sg_pass_action* pass_action, float width, float height) { - sg_begin_default_pass(pass_action, (int)width, (int)height); -} - -SOKOL_API_IMPL void sg_begin_pass(sg_pass pass_id, const sg_pass_action* pass_action) { - SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT(pass_action); - SOKOL_ASSERT((pass_action->_start_canary == 0) && (pass_action->_end_canary == 0)); - _sg.cur_pass = pass_id; - _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass && _sg_validate_begin_pass(pass)) { - _sg.pass_valid = true; - sg_pass_action pa; - _sg_resolve_default_pass_action(pass_action, &pa); - _sg_begin_pass(pass, &pa, pass->cmn.width, pass->cmn.height); - _SG_TRACE_ARGS(begin_pass, pass_id, &pa); - } else { - _sg.pass_valid = false; + SOKOL_ASSERT(!_sg.cur_pass.valid); + SOKOL_ASSERT(!_sg.cur_pass.in_pass); + SOKOL_ASSERT(pass); + SOKOL_ASSERT((pass->_start_canary == 0) && (pass->_end_canary == 0)); + const sg_pass pass_def = _sg_pass_defaults(pass); + if (!_sg_validate_begin_pass(&pass_def)) { + return; } + if (pass_def.attachments.id != SG_INVALID_ID) { + // an offscreen pass + SOKOL_ASSERT(_sg.cur_pass.atts == 0); + _sg.cur_pass.atts = _sg_lookup_attachments(&_sg.pools, pass_def.attachments.id); + if (0 == _sg.cur_pass.atts) { + _SG_ERROR(BEGINPASS_ATTACHMENT_INVALID); + return; + } + _sg.cur_pass.atts_id = pass_def.attachments; + _sg.cur_pass.width = _sg.cur_pass.atts->cmn.width; + _sg.cur_pass.height = _sg.cur_pass.atts->cmn.height; + } else { + // a swapchain pass + SOKOL_ASSERT(pass_def.swapchain.width > 0); + SOKOL_ASSERT(pass_def.swapchain.height > 0); + SOKOL_ASSERT(pass_def.swapchain.color_format > SG_PIXELFORMAT_NONE); + SOKOL_ASSERT(pass_def.swapchain.sample_count > 0); + _sg.cur_pass.width = pass_def.swapchain.width; + _sg.cur_pass.height = pass_def.swapchain.height; + _sg.cur_pass.swapchain.color_fmt = pass_def.swapchain.color_format; + _sg.cur_pass.swapchain.depth_fmt = pass_def.swapchain.depth_format; + _sg.cur_pass.swapchain.sample_count = pass_def.swapchain.sample_count; + } + _sg.cur_pass.valid = true; // may be overruled by backend begin-pass functions + _sg.cur_pass.in_pass = true; + _sg_begin_pass(&pass_def); + _SG_TRACE_ARGS(begin_pass, &pass_def); } SOKOL_API_IMPL void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left) { SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(_sg.cur_pass.in_pass); _sg_stats_add(num_apply_viewport, 1); - if (!_sg.pass_valid) { + if (!_sg.cur_pass.valid) { return; } _sg_apply_viewport(x, y, width, height, origin_top_left); @@ -17936,8 +17765,9 @@ SOKOL_API_IMPL void sg_apply_viewportf(float x, float y, float width, float heig SOKOL_API_IMPL void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left) { SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(_sg.cur_pass.in_pass); _sg_stats_add(num_apply_scissor_rect, 1); - if (!_sg.pass_valid) { + if (!_sg.cur_pass.valid) { return; } _sg_apply_scissor_rect(x, y, width, height, origin_top_left); @@ -17950,13 +17780,14 @@ SOKOL_API_IMPL void sg_apply_scissor_rectf(float x, float y, float width, float SOKOL_API_IMPL void sg_apply_pipeline(sg_pipeline pip_id) { SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(_sg.cur_pass.in_pass); _sg_stats_add(num_apply_pipeline, 1); - _sg.bindings_applied = false; + _sg.apply_bindings_called = false; if (!_sg_validate_apply_pipeline(pip_id)) { _sg.next_draw_valid = false; return; } - if (!_sg.pass_valid) { + if (!_sg.cur_pass.valid) { return; } _sg.cur_pipeline = pip_id; @@ -17970,14 +17801,18 @@ SOKOL_API_IMPL void sg_apply_pipeline(sg_pipeline pip_id) { SOKOL_API_IMPL void sg_apply_bindings(const sg_bindings* bindings) { SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(_sg.cur_pass.in_pass); SOKOL_ASSERT(bindings); SOKOL_ASSERT((bindings->_start_canary == 0) && (bindings->_end_canary==0)); _sg_stats_add(num_apply_bindings, 1); + _sg.apply_bindings_called = true; if (!_sg_validate_apply_bindings(bindings)) { _sg.next_draw_valid = false; return; } - _sg.bindings_applied = true; + if (!_sg.cur_pass.valid) { + return; + } _sg_bindings_t bnd; _sg_clear(&bnd, sizeof(bnd)); @@ -18072,6 +17907,7 @@ SOKOL_API_IMPL void sg_apply_bindings(const sg_bindings* bindings) { SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data) { SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(_sg.cur_pass.in_pass); SOKOL_ASSERT((stage == SG_SHADERSTAGE_VS) || (stage == SG_SHADERSTAGE_FS)); SOKOL_ASSERT((ub_index >= 0) && (ub_index < SG_MAX_SHADERSTAGE_UBS)); SOKOL_ASSERT(data && data->ptr && (data->size > 0)); @@ -18081,7 +17917,7 @@ SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const _sg.next_draw_valid = false; return; } - if (!_sg.pass_valid) { + if (!_sg.cur_pass.valid) { return; } if (!_sg.next_draw_valid) { @@ -18093,22 +17929,23 @@ SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const SOKOL_API_IMPL void sg_draw(int base_element, int num_elements, int num_instances) { SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(_sg.cur_pass.in_pass); SOKOL_ASSERT(base_element >= 0); SOKOL_ASSERT(num_elements >= 0); SOKOL_ASSERT(num_instances >= 0); _sg_stats_add(num_draw, 1); #if defined(SOKOL_DEBUG) - if (!_sg.bindings_applied) { + if (!_sg.apply_bindings_called) { _SG_WARN(DRAW_WITHOUT_BINDINGS); } #endif - if (!_sg.pass_valid) { + if (!_sg.cur_pass.valid) { return; } if (!_sg.next_draw_valid) { return; } - if (!_sg.bindings_applied) { + if (!_sg.apply_bindings_called) { return; } /* attempting to draw with zero elements or instances is not technically an @@ -18123,19 +17960,19 @@ SOKOL_API_IMPL void sg_draw(int base_element, int num_elements, int num_instance SOKOL_API_IMPL void sg_end_pass(void) { SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(_sg.cur_pass.in_pass); _sg_stats_add(num_passes, 1); - if (!_sg.pass_valid) { - return; - } + // NOTE: don't exit early if !_sg.cur_pass.valid _sg_end_pass(); - _sg.cur_pass.id = SG_INVALID_ID; _sg.cur_pipeline.id = SG_INVALID_ID; - _sg.pass_valid = false; + _sg_clear(&_sg.cur_pass, sizeof(_sg.cur_pass)); _SG_TRACE_NOARGS(end_pass); } SOKOL_API_IMPL void sg_commit(void) { SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(!_sg.cur_pass.valid); + SOKOL_ASSERT(!_sg.cur_pass.in_pass); _sg_commit(); _sg.stats.frame_index = _sg.frame_index; _sg.prev_stats = _sg.stats; @@ -18302,7 +18139,6 @@ SOKOL_API_IMPL sg_buffer_info sg_query_buffer_info(sg_buffer buf_id) { if (buf) { info.slot.state = buf->slot.state; info.slot.res_id = buf->slot.id; - info.slot.ctx_id = buf->slot.ctx_id; info.update_frame_index = buf->cmn.update_frame_index; info.append_frame_index = buf->cmn.append_frame_index; info.append_pos = buf->cmn.append_pos; @@ -18326,7 +18162,6 @@ SOKOL_API_IMPL sg_image_info sg_query_image_info(sg_image img_id) { if (img) { info.slot.state = img->slot.state; info.slot.res_id = img->slot.id; - info.slot.ctx_id = img->slot.ctx_id; info.upd_frame_index = img->cmn.upd_frame_index; #if defined(SOKOL_D3D11) info.num_slots = 1; @@ -18347,7 +18182,6 @@ SOKOL_API_IMPL sg_sampler_info sg_query_sampler_info(sg_sampler smp_id) { if (smp) { info.slot.state = smp->slot.state; info.slot.res_id = smp->slot.id; - info.slot.ctx_id = smp->slot.ctx_id; } return info; } @@ -18360,7 +18194,6 @@ SOKOL_API_IMPL sg_shader_info sg_query_shader_info(sg_shader shd_id) { if (shd) { info.slot.state = shd->slot.state; info.slot.res_id = shd->slot.id; - info.slot.ctx_id = shd->slot.ctx_id; } return info; } @@ -18373,20 +18206,18 @@ SOKOL_API_IMPL sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip_id) { if (pip) { info.slot.state = pip->slot.state; info.slot.res_id = pip->slot.id; - info.slot.ctx_id = pip->slot.ctx_id; } return info; } -SOKOL_API_IMPL sg_pass_info sg_query_pass_info(sg_pass pass_id) { +SOKOL_API_IMPL sg_attachments_info sg_query_attachments_info(sg_attachments atts_id) { SOKOL_ASSERT(_sg.valid); - sg_pass_info info; + sg_attachments_info info; _sg_clear(&info, sizeof(info)); - const _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass) { - info.slot.state = pass->slot.state; - info.slot.res_id = pass->slot.id; - info.slot.ctx_id = pass->slot.ctx_id; + const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); + if (atts) { + info.slot.state = atts->slot.state; + info.slot.res_id = atts->slot.id; } return info; } @@ -18510,20 +18341,20 @@ SOKOL_API_IMPL sg_pipeline_desc sg_query_pipeline_desc(sg_pipeline pip_id) { return desc; } -SOKOL_API_IMPL sg_pass_desc sg_query_pass_desc(sg_pass pass_id) { +SOKOL_API_IMPL sg_attachments_desc sg_query_attachments_desc(sg_attachments atts_id) { SOKOL_ASSERT(_sg.valid); - sg_pass_desc desc; + sg_attachments_desc desc; _sg_clear(&desc, sizeof(desc)); - const _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass) { - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - desc.color_attachments[i].image = pass->cmn.color_atts[i].image_id; - desc.color_attachments[i].mip_level = pass->cmn.color_atts[i].mip_level; - desc.color_attachments[i].slice = pass->cmn.color_atts[i].slice; + const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); + if (atts) { + for (int i = 0; i < atts->cmn.num_colors; i++) { + desc.colors[i].image = atts->cmn.colors[i].image_id; + desc.colors[i].mip_level = atts->cmn.colors[i].mip_level; + desc.colors[i].slice = atts->cmn.colors[i].slice; } - desc.depth_stencil_attachment.image = pass->cmn.ds_att.image_id; - desc.depth_stencil_attachment.mip_level = pass->cmn.ds_att.mip_level; - desc.depth_stencil_attachment.slice = pass->cmn.ds_att.slice; + desc.depth_stencil.image = atts->cmn.depth_stencil.image_id; + desc.depth_stencil.mip_level = atts->cmn.depth_stencil.mip_level; + desc.depth_stencil.slice = atts->cmn.depth_stencil.slice; } return desc; } @@ -18553,9 +18384,9 @@ SOKOL_API_IMPL sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_des return _sg_pipeline_desc_defaults(desc); } -SOKOL_API_IMPL sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc) { +SOKOL_API_IMPL sg_attachments_desc sg_query_attachments_defaults(const sg_attachments_desc* desc) { SOKOL_ASSERT(_sg.valid && desc); - return _sg_pass_desc_defaults(desc); + return _sg_attachments_desc_defaults(desc); } SOKOL_API_IMPL const void* sg_d3d11_device(void) { @@ -18660,21 +18491,21 @@ SOKOL_API_IMPL sg_d3d11_pipeline_info sg_d3d11_query_pipeline_info(sg_pipeline p return res; } -SOKOL_API_IMPL sg_d3d11_pass_info sg_d3d11_query_pass_info(sg_pass pass_id) { +SOKOL_API_IMPL sg_d3d11_attachments_info sg_d3d11_query_attachments_info(sg_attachments atts_id) { SOKOL_ASSERT(_sg.valid); - sg_d3d11_pass_info res; + sg_d3d11_attachments_info res; _sg_clear(&res, sizeof(res)); #if defined(SOKOL_D3D11) - const _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass) { + const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); + if (atts) { for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - res.color_rtv[i] = (const void*) pass->d3d11.color_atts[i].view.rtv; - res.resolve_rtv[i] = (const void*) pass->d3d11.resolve_atts[i].view.rtv; + res.color_rtv[i] = (const void*) atts->d3d11.colors[i].view.rtv; + res.resolve_rtv[i] = (const void*) atts->d3d11.resolves[i].view.rtv; } - res.dsv = (const void*) pass->d3d11.ds_att.view.dsv; + res.dsv = (const void*) atts->d3d11.depth_stencil.view.dsv; } #else - _SOKOL_UNUSED(pass_id); + _SOKOL_UNUSED(atts_id); #endif return res; } @@ -18920,21 +18751,21 @@ SOKOL_API_IMPL sg_wgpu_pipeline_info sg_wgpu_query_pipeline_info(sg_pipeline pip return res; } -SOKOL_API_IMPL sg_wgpu_pass_info sg_wgpu_query_pass_info(sg_pass pass_id) { +SOKOL_API_IMPL sg_wgpu_attachments_info sg_wgpu_query_attachments_info(sg_attachments atts_id) { SOKOL_ASSERT(_sg.valid); - sg_wgpu_pass_info res; + sg_wgpu_attachments_info res; _sg_clear(&res, sizeof(res)); #if defined(SOKOL_WGPU) - const _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass) { + const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); + if (atts) { for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - res.color_view[i] = (const void*) pass->wgpu.color_atts[i].view; - res.resolve_view[i] = (const void*) pass->wgpu.resolve_atts[i].view; + res.color_view[i] = (const void*) atts->wgpu.colors[i].view; + res.resolve_view[i] = (const void*) atts->wgpu.resolves[i].view; } - res.ds_view = (const void*) pass->wgpu.ds_att.view; + res.ds_view = (const void*) atts->wgpu.depth_stencil.view; } #else - _SOKOL_UNUSED(pass_id); + _SOKOL_UNUSED(atts_id); #endif return res; } @@ -19007,20 +18838,20 @@ SOKOL_API_IMPL sg_gl_shader_info sg_gl_query_shader_info(sg_shader shd_id) { return res; } -SOKOL_API_IMPL sg_gl_pass_info sg_gl_query_pass_info(sg_pass pass_id) { +SOKOL_API_IMPL sg_gl_attachments_info sg_gl_query_attachments_info(sg_attachments atts_id) { SOKOL_ASSERT(_sg.valid); - sg_gl_pass_info res; + sg_gl_attachments_info res; _sg_clear(&res, sizeof(res)); #if defined(_SOKOL_ANY_GL) - const _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass) { - res.frame_buffer = pass->gl.fb; + const _sg_attachments_t* atts = _sg_lookup_attachments(&_sg.pools, atts_id.id); + if (atts) { + res.framebuffer = atts->gl.fb; for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - res.msaa_resolve_framebuffer[i] = pass->gl.msaa_resolve_framebuffer[i]; + res.msaa_resolve_framebuffer[i] = atts->gl.msaa_resolve_framebuffer[i]; } } #else - _SOKOL_UNUSED(pass_id); + _SOKOL_UNUSED(atts_id); #endif return res; } diff --git a/src/sokol/c/sokol_glue.c b/src/sokol/c/sokol_glue.c new file mode 100644 index 0000000..95219dd --- /dev/null +++ b/src/sokol/c/sokol_glue.c @@ -0,0 +1,7 @@ +#if defined(IMPL) +#define SOKOL_GLUE_IMPL +#endif +#include "sokol_defines.h" +#include "sokol_app.h" +#include "sokol_gfx.h" +#include "sokol_glue.h" \ No newline at end of file diff --git a/src/sokol/c/sokol_glue.h b/src/sokol/c/sokol_glue.h new file mode 100644 index 0000000..b688a87 --- /dev/null +++ b/src/sokol/c/sokol_glue.h @@ -0,0 +1,162 @@ +#if defined(SOKOL_IMPL) && !defined(SOKOL_GLUE_IMPL) +#define SOKOL_GLUE_IMPL +#endif +#ifndef SOKOL_GLUE_INCLUDED +/* + sokol_glue.h -- glue helper functions for sokol headers + + Project URL: https://github.com/floooh/sokol + + Do this: + #define SOKOL_IMPL or + #define SOKOL_GLUE_IMPL + before you include this file in *one* C or C++ file to create the + implementation. + + ...optionally provide the following macros to override defaults: + + SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) + SOKOL_GLUE_API_DECL - public function declaration prefix (default: extern) + SOKOL_API_DECL - same as SOKOL_GLUE_API_DECL + SOKOL_API_IMPL - public function implementation prefix (default: -) + + If sokol_glue.h is compiled as a DLL, define the following before + including the declaration or implementation: + + SOKOL_DLL + + On Windows, SOKOL_DLL will define SOKOL_GLUE_API_DECL as __declspec(dllexport) + or __declspec(dllimport) as needed. + + OVERVIEW + ======== + sokol_glue.h provides glue helper functions between sokol_gfx.h and sokol_app.h, + so that sokol_gfx.h doesn't need to depend on sokol_app.h but can be + used with different window system glue libraries. + + PROVIDED FUNCTIONS + ================== + + sg_environment sglue_environment(void) + + Returns an sg_environment struct initialized by calling sokol_app.h + functions. Use this in the sg_setup() call like this: + + sg_setup(&(sg_desc){ + .environment = sglue_enviornment(), + ... + }); + + sg_swapchain sglue_swapchain(void) + + Returns an sg_swapchain struct initialized by calling sokol_app.h + functions. Use this in sg_begin_pass() for a 'swapchain pass' like + this: + + sg_begin_pass(&(sg_pass){ .swapchain = sglue_swapchain(), ... }); + + LICENSE + ======= + zlib/libpng license + + Copyright (c) 2018 Andre Weissflog + + 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, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software in a + product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ +#define SOKOL_GLUE_INCLUDED + +#if defined(SOKOL_API_DECL) && !defined(SOKOL_GLUE_API_DECL) +#define SOKOL_GLUE_API_DECL SOKOL_API_DECL +#endif +#ifndef SOKOL_GLUE_API_DECL +#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GLUE_IMPL) +#define SOKOL_GLUE_API_DECL __declspec(dllexport) +#elif defined(_WIN32) && defined(SOKOL_DLL) +#define SOKOL_GLUE_API_DECL __declspec(dllimport) +#else +#define SOKOL_GLUE_API_DECL extern +#endif +#endif + +#ifndef SOKOL_GFX_INCLUDED +#error "Please include sokol_gfx.h before sokol_glue.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +SOKOL_GLUE_API_DECL sg_environment sglue_environment(void); +SOKOL_GLUE_API_DECL sg_swapchain sglue_swapchain(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* SOKOL_GLUE_INCLUDED */ + +/*-- IMPLEMENTATION ----------------------------------------------------------*/ +#ifdef SOKOL_GLUE_IMPL +#define SOKOL_GLUE_IMPL_INCLUDED (1) +#include /* memset */ + +#ifndef SOKOL_APP_INCLUDED +#error "Please include sokol_app.h before the sokol_glue.h implementation" +#endif + +#ifndef SOKOL_API_IMPL +#define SOKOL_API_IMPL +#endif + + +SOKOL_API_IMPL sg_environment sglue_environment(void) { + sg_environment env; + memset(&env, 0, sizeof(env)); + env.defaults.color_format = (sg_pixel_format) sapp_color_format(); + env.defaults.depth_format = (sg_pixel_format) sapp_depth_format(); + env.defaults.sample_count = sapp_sample_count(); + env.metal.device = sapp_metal_get_device(); + env.d3d11.device = sapp_d3d11_get_device(); + env.d3d11.device_context = sapp_d3d11_get_device_context(); + env.wgpu.device = sapp_wgpu_get_device(); + return env; +} + +SOKOL_API_IMPL sg_swapchain sglue_swapchain(void) { + sg_swapchain swapchain; + memset(&swapchain, 0, sizeof(swapchain)); + swapchain.width = sapp_width(); + swapchain.height = sapp_height(); + swapchain.sample_count = sapp_sample_count(); + swapchain.color_format = (sg_pixel_format)sapp_color_format(); + swapchain.depth_format = (sg_pixel_format)sapp_depth_format(); + swapchain.metal.current_drawable = sapp_metal_get_current_drawable(); + swapchain.metal.depth_stencil_texture = sapp_metal_get_depth_stencil_texture(); + swapchain.metal.msaa_color_texture = sapp_metal_get_msaa_color_texture(); + swapchain.d3d11.render_view = sapp_d3d11_get_render_view(); + swapchain.d3d11.resolve_view = sapp_d3d11_get_resolve_view(); + swapchain.d3d11.depth_stencil_view = sapp_d3d11_get_depth_stencil_view(); + swapchain.wgpu.render_view = sapp_wgpu_get_render_view(); + swapchain.wgpu.resolve_view = sapp_wgpu_get_resolve_view(); + swapchain.wgpu.depth_stencil_view = sapp_wgpu_get_depth_stencil_view(); + swapchain.gl.framebuffer = sapp_gl_get_framebuffer(); + return swapchain; +} + +#endif /* SOKOL_GLUE_IMPL */ diff --git a/src/sokol/debugtext.d b/src/sokol/debugtext.d index 618e1d2..a7f4772 100644 --- a/src/sokol/debugtext.d +++ b/src/sokol/debugtext.d @@ -35,8 +35,8 @@ extern(C) struct ContextDesc { int max_commands = 0; int char_buf_size = 0; - float canvas_width = 0.0; - float canvas_height = 0.0; + float canvas_width = 0.0f; + float canvas_height = 0.0f; int tab_width = 0; sg.PixelFormat color_format; sg.PixelFormat depth_format; diff --git a/src/sokol/gfx.d b/src/sokol/gfx.d index 311aeb9..89d540d 100644 --- a/src/sokol/gfx.d +++ b/src/sokol/gfx.d @@ -23,11 +23,7 @@ struct Pipeline { uint id = 0; } extern(C) -struct Pass { - uint id = 0; -} -extern(C) -struct Context { +struct Attachments { uint id = 0; } extern(C) @@ -50,10 +46,10 @@ enum max_mipmaps = 16; enum max_texturearray_layers = 128; extern(C) struct Color { - float r = 0.0; - float g = 0.0; - float b = 0.0; - float a = 0.0; + float r = 0.0f; + float g = 0.0f; + float b = 0.0f; + float a = 0.0f; } enum Backend { Glcore33, @@ -164,7 +160,7 @@ struct Limits { int max_image_size_array = 0; int max_image_array_layers = 0; int max_vertex_attrs = 0; - int gl_max_vertex_uniform_vectors = 0; + int gl_max_vertex_uniform_components = 0; int gl_max_combined_texture_image_units = 0; } enum ResourceState { @@ -411,7 +407,7 @@ extern(C) struct DepthAttachmentAction { LoadAction load_action; StoreAction store_action; - float clear_value = 0.0; + float clear_value = 0.0f; } extern(C) struct StencilAttachmentAction { @@ -421,10 +417,51 @@ struct StencilAttachmentAction { } extern(C) struct PassAction { - uint _start_canary = 0; ColorAttachmentAction[4] colors; DepthAttachmentAction depth; StencilAttachmentAction stencil; +} +extern(C) +struct MetalSwapchain { + const(void)* current_drawable = null; + const(void)* depth_stencil_texture = null; + const(void)* msaa_color_texture = null; +} +extern(C) +struct D3d11Swapchain { + const(void)* render_view = null; + const(void)* resolve_view = null; + const(void)* depth_stencil_view = null; +} +extern(C) +struct WgpuSwapchain { + const(void)* render_view = null; + const(void)* resolve_view = null; + const(void)* depth_stencil_view = null; +} +extern(C) +struct GlSwapchain { + uint framebuffer = 0; +} +extern(C) +struct Swapchain { + int width = 0; + int height = 0; + int sample_count = 0; + PixelFormat color_format; + PixelFormat depth_format; + MetalSwapchain metal; + D3d11Swapchain d3d11; + WgpuSwapchain wgpu; + GlSwapchain gl; +} +extern(C) +struct Pass { + uint _start_canary = 0; + PassAction action; + Attachments attachments; + Swapchain swapchain; + const(char)* label = null; uint _end_canary = 0; } extern(C) @@ -493,8 +530,8 @@ struct SamplerDesc { Wrap wrap_u; Wrap wrap_v; Wrap wrap_w; - float min_lod = 0.0; - float max_lod = 0.0; + float min_lod = 0.0f; + float max_lod = 0.0f; BorderColor border_color; CompareFunc compare; uint max_anisotropy = 0; @@ -600,9 +637,9 @@ struct DepthState { PixelFormat pixel_format; CompareFunc compare; bool write_enabled = false; - float bias = 0.0; - float bias_slope_scale = 0.0; - float bias_clamp = 0.0; + float bias = 0.0f; + float bias_slope_scale = 0.0f; + float bias_clamp = 0.0f; } extern(C) struct BlendState { @@ -640,17 +677,17 @@ struct PipelineDesc { uint _end_canary = 0; } extern(C) -struct PassAttachmentDesc { +struct AttachmentDesc { Image image; int mip_level = 0; int slice = 0; } extern(C) -struct PassDesc { +struct AttachmentsDesc { uint _start_canary = 0; - PassAttachmentDesc[4] color_attachments; - PassAttachmentDesc[4] resolve_attachments; - PassAttachmentDesc depth_stencil_attachment; + AttachmentDesc[4] colors; + AttachmentDesc[4] resolves; + AttachmentDesc depth_stencil; const(char)* label = null; uint _end_canary = 0; } @@ -663,18 +700,17 @@ struct TraceHooks { extern(C) void function(const SamplerDesc *, Sampler, void*) make_sampler = null; extern(C) void function(const ShaderDesc *, Shader, void*) make_shader = null; extern(C) void function(const PipelineDesc *, Pipeline, void*) make_pipeline = null; - extern(C) void function(const PassDesc *, Pass, void*) make_pass = null; + extern(C) void function(const AttachmentsDesc *, Attachments, void*) make_attachments = null; extern(C) void function(Buffer, void*) destroy_buffer = null; extern(C) void function(Image, void*) destroy_image = null; extern(C) void function(Sampler, void*) destroy_sampler = null; extern(C) void function(Shader, void*) destroy_shader = null; extern(C) void function(Pipeline, void*) destroy_pipeline = null; - extern(C) void function(Pass, void*) destroy_pass = null; + extern(C) void function(Attachments, void*) destroy_attachments = null; extern(C) void function(Buffer, const Range *, void*) update_buffer = null; extern(C) void function(Image, const ImageData *, void*) update_image = null; extern(C) void function(Buffer, const Range *, int, void*) append_buffer = null; - extern(C) void function(const PassAction *, int, int, void*) begin_default_pass = null; - extern(C) void function(Pass, const PassAction *, void*) begin_pass = null; + extern(C) void function(const Pass *, void*) begin_pass = null; extern(C) void function(int, int, int, int, bool, void*) apply_viewport = null; extern(C) void function(int, int, int, int, bool, void*) apply_scissor_rect = null; extern(C) void function(Pipeline, void*) apply_pipeline = null; @@ -688,31 +724,31 @@ struct TraceHooks { extern(C) void function(Sampler, void*) alloc_sampler = null; extern(C) void function(Shader, void*) alloc_shader = null; extern(C) void function(Pipeline, void*) alloc_pipeline = null; - extern(C) void function(Pass, void*) alloc_pass = null; + extern(C) void function(Attachments, void*) alloc_attachments = null; extern(C) void function(Buffer, void*) dealloc_buffer = null; extern(C) void function(Image, void*) dealloc_image = null; extern(C) void function(Sampler, void*) dealloc_sampler = null; extern(C) void function(Shader, void*) dealloc_shader = null; extern(C) void function(Pipeline, void*) dealloc_pipeline = null; - extern(C) void function(Pass, void*) dealloc_pass = null; + extern(C) void function(Attachments, void*) dealloc_attachments = null; extern(C) void function(Buffer, const BufferDesc *, void*) init_buffer = null; extern(C) void function(Image, const ImageDesc *, void*) init_image = null; extern(C) void function(Sampler, const SamplerDesc *, void*) init_sampler = null; extern(C) void function(Shader, const ShaderDesc *, void*) init_shader = null; extern(C) void function(Pipeline, const PipelineDesc *, void*) init_pipeline = null; - extern(C) void function(Pass, const PassDesc *, void*) init_pass = null; + extern(C) void function(Attachments, const AttachmentsDesc *, void*) init_attachments = null; extern(C) void function(Buffer, void*) uninit_buffer = null; extern(C) void function(Image, void*) uninit_image = null; extern(C) void function(Sampler, void*) uninit_sampler = null; extern(C) void function(Shader, void*) uninit_shader = null; extern(C) void function(Pipeline, void*) uninit_pipeline = null; - extern(C) void function(Pass, void*) uninit_pass = null; + extern(C) void function(Attachments, void*) uninit_attachments = null; extern(C) void function(Buffer, void*) fail_buffer = null; extern(C) void function(Image, void*) fail_image = null; extern(C) void function(Sampler, void*) fail_sampler = null; extern(C) void function(Shader, void*) fail_shader = null; extern(C) void function(Pipeline, void*) fail_pipeline = null; - extern(C) void function(Pass, void*) fail_pass = null; + extern(C) void function(Attachments, void*) fail_attachments = null; extern(C) void function(scope const(char)*, void*) push_debug_group = null; extern(C) void function(void*) pop_debug_group = null; } @@ -720,7 +756,6 @@ extern(C) struct SlotInfo { ResourceState state; uint res_id = 0; - uint ctx_id = 0; } extern(C) struct BufferInfo { @@ -752,7 +787,7 @@ struct PipelineInfo { SlotInfo slot; } extern(C) -struct PassInfo { +struct AttachmentsInfo { SlotInfo slot; } extern(C) @@ -967,13 +1002,7 @@ enum LogItem { Wgpu_shader_create_bindgroup_layout_failed, Wgpu_create_pipeline_layout_failed, Wgpu_create_render_pipeline_failed, - Wgpu_pass_create_texture_view_failed, - Uninit_buffer_active_context_mismatch, - Uninit_image_active_context_mismatch, - Uninit_sampler_active_context_mismatch, - Uninit_shader_active_context_mismatch, - Uninit_pipeline_active_context_mismatch, - Uninit_pass_active_context_mismatch, + Wgpu_attachments_create_texture_view_failed, Identical_commit_listener, Commit_listener_array_full, Trace_hooks_not_enabled, @@ -982,31 +1011,32 @@ enum LogItem { Dealloc_sampler_invalid_state, Dealloc_shader_invalid_state, Dealloc_pipeline_invalid_state, - Dealloc_pass_invalid_state, + Dealloc_attachments_invalid_state, Init_buffer_invalid_state, Init_image_invalid_state, Init_sampler_invalid_state, Init_shader_invalid_state, Init_pipeline_invalid_state, - Init_pass_invalid_state, + Init_attachments_invalid_state, Uninit_buffer_invalid_state, Uninit_image_invalid_state, Uninit_sampler_invalid_state, Uninit_shader_invalid_state, Uninit_pipeline_invalid_state, - Uninit_pass_invalid_state, + Uninit_attachments_invalid_state, Fail_buffer_invalid_state, Fail_image_invalid_state, Fail_sampler_invalid_state, Fail_shader_invalid_state, Fail_pipeline_invalid_state, - Fail_pass_invalid_state, + Fail_attachments_invalid_state, Buffer_pool_exhausted, Image_pool_exhausted, Sampler_pool_exhausted, Shader_pool_exhausted, Pipeline_pool_exhausted, Pass_pool_exhausted, + Beginpass_attachment_invalid, Draw_without_bindings, Validate_bufferdesc_canary, Validate_bufferdesc_size, @@ -1066,46 +1096,78 @@ enum LogItem { Validate_pipelinedesc_no_attrs, Validate_pipelinedesc_layout_stride4, Validate_pipelinedesc_attr_semantics, - Validate_passdesc_canary, - Validate_passdesc_no_attachments, - Validate_passdesc_no_cont_color_atts, - Validate_passdesc_image, - Validate_passdesc_miplevel, - Validate_passdesc_face, - Validate_passdesc_layer, - Validate_passdesc_slice, - Validate_passdesc_image_no_rt, - Validate_passdesc_color_inv_pixelformat, - Validate_passdesc_depth_inv_pixelformat, - Validate_passdesc_image_sizes, - Validate_passdesc_image_sample_counts, - Validate_passdesc_resolve_color_image_msaa, - Validate_passdesc_resolve_image, - Validate_passdesc_resolve_sample_count, - Validate_passdesc_resolve_miplevel, - Validate_passdesc_resolve_face, - Validate_passdesc_resolve_layer, - Validate_passdesc_resolve_slice, - Validate_passdesc_resolve_image_no_rt, - Validate_passdesc_resolve_image_sizes, - Validate_passdesc_resolve_image_format, - Validate_passdesc_depth_image, - Validate_passdesc_depth_miplevel, - Validate_passdesc_depth_face, - Validate_passdesc_depth_layer, - Validate_passdesc_depth_slice, - Validate_passdesc_depth_image_no_rt, - Validate_passdesc_depth_image_sizes, - Validate_passdesc_depth_image_sample_count, - Validate_beginpass_pass, + Validate_attachmentsdesc_canary, + Validate_attachmentsdesc_no_attachments, + Validate_attachmentsdesc_no_cont_color_atts, + Validate_attachmentsdesc_image, + Validate_attachmentsdesc_miplevel, + Validate_attachmentsdesc_face, + Validate_attachmentsdesc_layer, + Validate_attachmentsdesc_slice, + Validate_attachmentsdesc_image_no_rt, + Validate_attachmentsdesc_color_inv_pixelformat, + Validate_attachmentsdesc_depth_inv_pixelformat, + Validate_attachmentsdesc_image_sizes, + Validate_attachmentsdesc_image_sample_counts, + Validate_attachmentsdesc_resolve_color_image_msaa, + Validate_attachmentsdesc_resolve_image, + Validate_attachmentsdesc_resolve_sample_count, + Validate_attachmentsdesc_resolve_miplevel, + Validate_attachmentsdesc_resolve_face, + Validate_attachmentsdesc_resolve_layer, + Validate_attachmentsdesc_resolve_slice, + Validate_attachmentsdesc_resolve_image_no_rt, + Validate_attachmentsdesc_resolve_image_sizes, + Validate_attachmentsdesc_resolve_image_format, + Validate_attachmentsdesc_depth_image, + Validate_attachmentsdesc_depth_miplevel, + Validate_attachmentsdesc_depth_face, + Validate_attachmentsdesc_depth_layer, + Validate_attachmentsdesc_depth_slice, + Validate_attachmentsdesc_depth_image_no_rt, + Validate_attachmentsdesc_depth_image_sizes, + Validate_attachmentsdesc_depth_image_sample_count, + Validate_beginpass_canary, + Validate_beginpass_attachments_exists, + Validate_beginpass_attachments_valid, Validate_beginpass_color_attachment_image, Validate_beginpass_resolve_attachment_image, Validate_beginpass_depthstencil_attachment_image, + Validate_beginpass_swapchain_expect_width, + Validate_beginpass_swapchain_expect_width_notset, + Validate_beginpass_swapchain_expect_height, + Validate_beginpass_swapchain_expect_height_notset, + Validate_beginpass_swapchain_expect_samplecount, + Validate_beginpass_swapchain_expect_samplecount_notset, + Validate_beginpass_swapchain_expect_colorformat, + Validate_beginpass_swapchain_expect_colorformat_notset, + Validate_beginpass_swapchain_expect_depthformat_notset, + Validate_beginpass_swapchain_metal_expect_currentdrawable, + Validate_beginpass_swapchain_metal_expect_currentdrawable_notset, + Validate_beginpass_swapchain_metal_expect_depthstenciltexture, + Validate_beginpass_swapchain_metal_expect_depthstenciltexture_notset, + Validate_beginpass_swapchain_metal_expect_msaacolortexture, + Validate_beginpass_swapchain_metal_expect_msaacolortexture_notset, + Validate_beginpass_swapchain_d3d11_expect_renderview, + Validate_beginpass_swapchain_d3d11_expect_renderview_notset, + Validate_beginpass_swapchain_d3d11_expect_resolveview, + Validate_beginpass_swapchain_d3d11_expect_resolveview_notset, + Validate_beginpass_swapchain_d3d11_expect_depthstencilview, + Validate_beginpass_swapchain_d3d11_expect_depthstencilview_notset, + Validate_beginpass_swapchain_wgpu_expect_renderview, + Validate_beginpass_swapchain_wgpu_expect_renderview_notset, + Validate_beginpass_swapchain_wgpu_expect_resolveview, + Validate_beginpass_swapchain_wgpu_expect_resolveview_notset, + Validate_beginpass_swapchain_wgpu_expect_depthstencilview, + Validate_beginpass_swapchain_wgpu_expect_depthstencilview_notset, + Validate_beginpass_swapchain_gl_expect_framebuffer_notset, Validate_apip_pipeline_valid_id, Validate_apip_pipeline_exists, Validate_apip_pipeline_valid, Validate_apip_shader_exists, Validate_apip_shader_valid, + Validate_apip_curpass_attachments_exists, + Validate_apip_curpass_attachments_valid, Validate_apip_att_count, Validate_apip_color_format, Validate_apip_depth_format, @@ -1163,50 +1225,30 @@ enum LogItem { Validation_failed, } extern(C) -struct MetalContextDesc { - const(void)* device = null; - extern(C) const(void)* function() renderpass_descriptor_cb = null; - extern(C) const(void)* function(void*) renderpass_descriptor_userdata_cb = null; - extern(C) const(void)* function() drawable_cb = null; - extern(C) const(void)* function(void*) drawable_userdata_cb = null; - void* user_data = null; +struct EnvironmentDefaults { + PixelFormat color_format; + PixelFormat depth_format; + int sample_count = 0; } extern(C) -struct D3d11ContextDesc { +struct MetalEnvironment { const(void)* device = null; - const(void)* device_context = null; - extern(C) const(void)* function() render_target_view_cb = null; - extern(C) const(void)* function(void*) render_target_view_userdata_cb = null; - extern(C) const(void)* function() depth_stencil_view_cb = null; - extern(C) const(void)* function(void*) depth_stencil_view_userdata_cb = null; - void* user_data = null; } extern(C) -struct WgpuContextDesc { +struct D3d11Environment { const(void)* device = null; - extern(C) const(void)* function() render_view_cb = null; - extern(C) const(void)* function(void*) render_view_userdata_cb = null; - extern(C) const(void)* function() resolve_view_cb = null; - extern(C) const(void)* function(void*) resolve_view_userdata_cb = null; - extern(C) const(void)* function() depth_stencil_view_cb = null; - extern(C) const(void)* function(void*) depth_stencil_view_userdata_cb = null; - void* user_data = null; + const(void)* device_context = null; } extern(C) -struct GlContextDesc { - extern(C) uint function() default_framebuffer_cb = null; - extern(C) uint function(void*) default_framebuffer_userdata_cb = null; - void* user_data = null; +struct WgpuEnvironment { + const(void)* device = null; } extern(C) -struct ContextDesc { - int color_format = 0; - int depth_format = 0; - int sample_count = 0; - MetalContextDesc metal; - D3d11ContextDesc d3d11; - WgpuContextDesc wgpu; - GlContextDesc gl; +struct Environment { + EnvironmentDefaults defaults; + MetalEnvironment metal; + D3d11Environment d3d11; + WgpuEnvironment wgpu; } extern(C) struct CommitListener { @@ -1232,17 +1274,17 @@ struct Desc { int sampler_pool_size = 0; int shader_pool_size = 0; int pipeline_pool_size = 0; - int pass_pool_size = 0; - int context_pool_size = 0; + int attachments_pool_size = 0; int uniform_buffer_size = 0; int max_commit_listeners = 0; bool disable_validation = false; bool mtl_force_managed_storage_mode = false; + bool mtl_use_command_buffer_with_retained_references = false; bool wgpu_disable_bindgroups_cache = false; int wgpu_bindgroups_cache_size = 0; Allocator allocator; Logger logger; - ContextDesc context; + Environment environment; uint _end_canary = 0; } extern(C) void sg_setup(const Desc *) @system @nogc nothrow; @@ -1301,9 +1343,9 @@ extern(C) Pipeline sg_make_pipeline(const PipelineDesc *) @system @nogc nothrow; Pipeline makePipeline(ref PipelineDesc desc) @trusted @nogc nothrow { return sg_make_pipeline(&desc); } -extern(C) Pass sg_make_pass(const PassDesc *) @system @nogc nothrow; -Pass makePass(ref PassDesc desc) @trusted @nogc nothrow { - return sg_make_pass(&desc); +extern(C) Attachments sg_make_attachments(const AttachmentsDesc *) @system @nogc nothrow; +Attachments makeAttachments(ref AttachmentsDesc desc) @trusted @nogc nothrow { + return sg_make_attachments(&desc); } extern(C) void sg_destroy_buffer(Buffer) @system @nogc nothrow; void destroyBuffer(Buffer buf) @trusted @nogc nothrow { @@ -1325,9 +1367,9 @@ extern(C) void sg_destroy_pipeline(Pipeline) @system @nogc nothrow; void destroyPipeline(Pipeline pip) @trusted @nogc nothrow { sg_destroy_pipeline(pip); } -extern(C) void sg_destroy_pass(Pass) @system @nogc nothrow; -void destroyPass(Pass pass) @trusted @nogc nothrow { - sg_destroy_pass(pass); +extern(C) void sg_destroy_attachments(Attachments) @system @nogc nothrow; +void destroyAttachments(Attachments atts) @trusted @nogc nothrow { + sg_destroy_attachments(atts); } extern(C) void sg_update_buffer(Buffer, const Range *) @system @nogc nothrow; void updateBuffer(Buffer buf, ref Range data) @trusted @nogc nothrow { @@ -1349,17 +1391,9 @@ extern(C) bool sg_query_buffer_will_overflow(Buffer, size_t) @system @nogc nothr bool queryBufferWillOverflow(Buffer buf, size_t size) @trusted @nogc nothrow { return sg_query_buffer_will_overflow(buf, size); } -extern(C) void sg_begin_default_pass(const PassAction *, int, int) @system @nogc nothrow; -void beginDefaultPass(ref PassAction pass_action, int width, int height) @trusted @nogc nothrow { - sg_begin_default_pass(&pass_action, width, height); -} -extern(C) void sg_begin_default_passf(const PassAction *, float, float) @system @nogc nothrow; -void beginDefaultPassf(ref PassAction pass_action, float width, float height) @trusted @nogc nothrow { - sg_begin_default_passf(&pass_action, width, height); -} -extern(C) void sg_begin_pass(Pass, const PassAction *) @system @nogc nothrow; -void beginPass(Pass pass, ref PassAction pass_action) @trusted @nogc nothrow { - sg_begin_pass(pass, &pass_action); +extern(C) void sg_begin_pass(const Pass *) @system @nogc nothrow; +void beginPass(ref Pass pass) @trusted @nogc nothrow { + sg_begin_pass(&pass); } extern(C) void sg_apply_viewport(int, int, int, int, bool) @system @nogc nothrow; void applyViewport(int x, int y, int width, int height, bool origin_top_left) @trusted @nogc nothrow { @@ -1449,9 +1483,9 @@ extern(C) ResourceState sg_query_pipeline_state(Pipeline) @system @nogc nothrow; ResourceState queryPipelineState(Pipeline pip) @trusted @nogc nothrow { return sg_query_pipeline_state(pip); } -extern(C) ResourceState sg_query_pass_state(Pass) @system @nogc nothrow; -ResourceState queryPassState(Pass pass) @trusted @nogc nothrow { - return sg_query_pass_state(pass); +extern(C) ResourceState sg_query_attachments_state(Attachments) @system @nogc nothrow; +ResourceState queryAttachmentsState(Attachments atts) @trusted @nogc nothrow { + return sg_query_attachments_state(atts); } extern(C) BufferInfo sg_query_buffer_info(Buffer) @system @nogc nothrow; BufferInfo queryBufferInfo(Buffer buf) @trusted @nogc nothrow { @@ -1473,9 +1507,9 @@ extern(C) PipelineInfo sg_query_pipeline_info(Pipeline) @system @nogc nothrow; PipelineInfo queryPipelineInfo(Pipeline pip) @trusted @nogc nothrow { return sg_query_pipeline_info(pip); } -extern(C) PassInfo sg_query_pass_info(Pass) @system @nogc nothrow; -PassInfo queryPassInfo(Pass pass) @trusted @nogc nothrow { - return sg_query_pass_info(pass); +extern(C) AttachmentsInfo sg_query_attachments_info(Attachments) @system @nogc nothrow; +AttachmentsInfo queryAttachmentsInfo(Attachments atts) @trusted @nogc nothrow { + return sg_query_attachments_info(atts); } extern(C) BufferDesc sg_query_buffer_desc(Buffer) @system @nogc nothrow; BufferDesc queryBufferDesc(Buffer buf) @trusted @nogc nothrow { @@ -1497,9 +1531,9 @@ extern(C) PipelineDesc sg_query_pipeline_desc(Pipeline) @system @nogc nothrow; PipelineDesc queryPipelineDesc(Pipeline pip) @trusted @nogc nothrow { return sg_query_pipeline_desc(pip); } -extern(C) PassDesc sg_query_pass_desc(Pass) @system @nogc nothrow; -PassDesc queryPassDesc(Pass pass) @trusted @nogc nothrow { - return sg_query_pass_desc(pass); +extern(C) AttachmentsDesc sg_query_attachments_desc(Attachments) @system @nogc nothrow; +AttachmentsDesc queryAttachmentsDesc(Attachments atts) @trusted @nogc nothrow { + return sg_query_attachments_desc(atts); } extern(C) BufferDesc sg_query_buffer_defaults(const BufferDesc *) @system @nogc nothrow; BufferDesc queryBufferDefaults(ref BufferDesc desc) @trusted @nogc nothrow { @@ -1521,9 +1555,9 @@ extern(C) PipelineDesc sg_query_pipeline_defaults(const PipelineDesc *) @system PipelineDesc queryPipelineDefaults(ref PipelineDesc desc) @trusted @nogc nothrow { return sg_query_pipeline_defaults(&desc); } -extern(C) PassDesc sg_query_pass_defaults(const PassDesc *) @system @nogc nothrow; -PassDesc queryPassDefaults(ref PassDesc desc) @trusted @nogc nothrow { - return sg_query_pass_defaults(&desc); +extern(C) AttachmentsDesc sg_query_attachments_defaults(const AttachmentsDesc *) @system @nogc nothrow; +AttachmentsDesc queryAttachmentsDefaults(ref AttachmentsDesc desc) @trusted @nogc nothrow { + return sg_query_attachments_defaults(&desc); } extern(C) Buffer sg_alloc_buffer() @system @nogc nothrow; Buffer allocBuffer() @trusted @nogc nothrow { @@ -1545,9 +1579,9 @@ extern(C) Pipeline sg_alloc_pipeline() @system @nogc nothrow; Pipeline allocPipeline() @trusted @nogc nothrow { return sg_alloc_pipeline(); } -extern(C) Pass sg_alloc_pass() @system @nogc nothrow; -Pass allocPass() @trusted @nogc nothrow { - return sg_alloc_pass(); +extern(C) Attachments sg_alloc_attachments() @system @nogc nothrow; +Attachments allocAttachments() @trusted @nogc nothrow { + return sg_alloc_attachments(); } extern(C) void sg_dealloc_buffer(Buffer) @system @nogc nothrow; void deallocBuffer(Buffer buf) @trusted @nogc nothrow { @@ -1569,9 +1603,9 @@ extern(C) void sg_dealloc_pipeline(Pipeline) @system @nogc nothrow; void deallocPipeline(Pipeline pip) @trusted @nogc nothrow { sg_dealloc_pipeline(pip); } -extern(C) void sg_dealloc_pass(Pass) @system @nogc nothrow; -void deallocPass(Pass pass) @trusted @nogc nothrow { - sg_dealloc_pass(pass); +extern(C) void sg_dealloc_attachments(Attachments) @system @nogc nothrow; +void deallocAttachments(Attachments attachments) @trusted @nogc nothrow { + sg_dealloc_attachments(attachments); } extern(C) void sg_init_buffer(Buffer, const BufferDesc *) @system @nogc nothrow; void initBuffer(Buffer buf, ref BufferDesc desc) @trusted @nogc nothrow { @@ -1593,9 +1627,9 @@ extern(C) void sg_init_pipeline(Pipeline, const PipelineDesc *) @system @nogc no void initPipeline(Pipeline pip, ref PipelineDesc desc) @trusted @nogc nothrow { sg_init_pipeline(pip, &desc); } -extern(C) void sg_init_pass(Pass, const PassDesc *) @system @nogc nothrow; -void initPass(Pass pass, ref PassDesc desc) @trusted @nogc nothrow { - sg_init_pass(pass, &desc); +extern(C) void sg_init_attachments(Attachments, const AttachmentsDesc *) @system @nogc nothrow; +void initAttachments(Attachments attachments, ref AttachmentsDesc desc) @trusted @nogc nothrow { + sg_init_attachments(attachments, &desc); } extern(C) void sg_uninit_buffer(Buffer) @system @nogc nothrow; void uninitBuffer(Buffer buf) @trusted @nogc nothrow { @@ -1617,9 +1651,9 @@ extern(C) void sg_uninit_pipeline(Pipeline) @system @nogc nothrow; void uninitPipeline(Pipeline pip) @trusted @nogc nothrow { sg_uninit_pipeline(pip); } -extern(C) void sg_uninit_pass(Pass) @system @nogc nothrow; -void uninitPass(Pass pass) @trusted @nogc nothrow { - sg_uninit_pass(pass); +extern(C) void sg_uninit_attachments(Attachments) @system @nogc nothrow; +void uninitAttachments(Attachments atts) @trusted @nogc nothrow { + sg_uninit_attachments(atts); } extern(C) void sg_fail_buffer(Buffer) @system @nogc nothrow; void failBuffer(Buffer buf) @trusted @nogc nothrow { @@ -1641,9 +1675,9 @@ extern(C) void sg_fail_pipeline(Pipeline) @system @nogc nothrow; void failPipeline(Pipeline pip) @trusted @nogc nothrow { sg_fail_pipeline(pip); } -extern(C) void sg_fail_pass(Pass) @system @nogc nothrow; -void failPass(Pass pass) @trusted @nogc nothrow { - sg_fail_pass(pass); +extern(C) void sg_fail_attachments(Attachments) @system @nogc nothrow; +void failAttachments(Attachments atts) @trusted @nogc nothrow { + sg_fail_attachments(atts); } extern(C) void sg_enable_frame_stats() @system @nogc nothrow; void enableFrameStats() @trusted @nogc nothrow { @@ -1661,18 +1695,6 @@ extern(C) FrameStats sg_query_frame_stats() @system @nogc nothrow; FrameStats queryFrameStats() @trusted @nogc nothrow { return sg_query_frame_stats(); } -extern(C) Context sg_setup_context() @system @nogc nothrow; -Context setupContext() @trusted @nogc nothrow { - return sg_setup_context(); -} -extern(C) void sg_activate_context(Context) @system @nogc nothrow; -void activateContext(Context ctx_id) @trusted @nogc nothrow { - sg_activate_context(ctx_id); -} -extern(C) void sg_discard_context(Context) @system @nogc nothrow; -void discardContext(Context ctx_id) @trusted @nogc nothrow { - sg_discard_context(ctx_id); -} extern(C) struct D3d11BufferInfo { const(void)* buf = null; @@ -1703,7 +1725,7 @@ struct D3d11PipelineInfo { const(void)* bs = null; } extern(C) -struct D3d11PassInfo { +struct D3d11AttachmentsInfo { const(void)*[4] color_rtv = null; const(void)*[4] resolve_rtv = null; const(void)* dsv = null; @@ -1758,7 +1780,7 @@ struct WgpuPipelineInfo { const(void)* pip = null; } extern(C) -struct WgpuPassInfo { +struct WgpuAttachmentsInfo { const(void)*[4] color_view = null; const(void)*[4] resolve_view = null; const(void)* ds_view = null; @@ -1784,8 +1806,8 @@ struct GlShaderInfo { uint prog = 0; } extern(C) -struct GlPassInfo { - uint frame_buffer = 0; +struct GlAttachmentsInfo { + uint framebuffer = 0; uint[4] msaa_resolve_framebuffer = 0; } extern(C) scope const(void)* sg_d3d11_device() @system @nogc nothrow; @@ -1816,9 +1838,9 @@ extern(C) D3d11PipelineInfo sg_d3d11_query_pipeline_info(Pipeline) @system @nogc D3d11PipelineInfo d3d11QueryPipelineInfo(Pipeline pip) @trusted @nogc nothrow { return sg_d3d11_query_pipeline_info(pip); } -extern(C) D3d11PassInfo sg_d3d11_query_pass_info(Pass) @system @nogc nothrow; -D3d11PassInfo d3d11QueryPassInfo(Pass pass) @trusted @nogc nothrow { - return sg_d3d11_query_pass_info(pass); +extern(C) D3d11AttachmentsInfo sg_d3d11_query_attachments_info(Attachments) @system @nogc nothrow; +D3d11AttachmentsInfo d3d11QueryAttachmentsInfo(Attachments atts) @trusted @nogc nothrow { + return sg_d3d11_query_attachments_info(atts); } extern(C) scope const(void)* sg_mtl_device() @system @nogc nothrow; scope const(void)* mtlDevice() @trusted @nogc nothrow { @@ -1884,9 +1906,9 @@ extern(C) WgpuPipelineInfo sg_wgpu_query_pipeline_info(Pipeline) @system @nogc n WgpuPipelineInfo wgpuQueryPipelineInfo(Pipeline pip) @trusted @nogc nothrow { return sg_wgpu_query_pipeline_info(pip); } -extern(C) WgpuPassInfo sg_wgpu_query_pass_info(Pass) @system @nogc nothrow; -WgpuPassInfo wgpuQueryPassInfo(Pass pass) @trusted @nogc nothrow { - return sg_wgpu_query_pass_info(pass); +extern(C) WgpuAttachmentsInfo sg_wgpu_query_attachments_info(Attachments) @system @nogc nothrow; +WgpuAttachmentsInfo wgpuQueryAttachmentsInfo(Attachments atts) @trusted @nogc nothrow { + return sg_wgpu_query_attachments_info(atts); } extern(C) GlBufferInfo sg_gl_query_buffer_info(Buffer) @system @nogc nothrow; GlBufferInfo glQueryBufferInfo(Buffer buf) @trusted @nogc nothrow { @@ -1904,7 +1926,7 @@ extern(C) GlShaderInfo sg_gl_query_shader_info(Shader) @system @nogc nothrow; GlShaderInfo glQueryShaderInfo(Shader shd) @trusted @nogc nothrow { return sg_gl_query_shader_info(shd); } -extern(C) GlPassInfo sg_gl_query_pass_info(Pass) @system @nogc nothrow; -GlPassInfo glQueryPassInfo(Pass pass) @trusted @nogc nothrow { - return sg_gl_query_pass_info(pass); +extern(C) GlAttachmentsInfo sg_gl_query_attachments_info(Attachments) @system @nogc nothrow; +GlAttachmentsInfo glQueryAttachmentsInfo(Attachments atts) @trusted @nogc nothrow { + return sg_gl_query_attachments_info(atts); } diff --git a/src/sokol/glue.d b/src/sokol/glue.d index e42a333..edccf90 100644 --- a/src/sokol/glue.d +++ b/src/sokol/glue.d @@ -1,30 +1,13 @@ -module sokol.glue; +// machine generated, do not edit +module sokol.glue; import sg = sokol.gfx; -import sapp = sokol.app; -extern(C) sg.ContextDesc context() @trusted @nogc nothrow { - sg.ContextDesc ctx = { - color_format: sapp.colorFormat(), - depth_format: sapp.depthFormat(), - sample_count: sapp.sampleCount(), - metal: { - device: sapp.metalGetDevice(), - renderpass_descriptor_cb: &sapp.sapp_metal_get_renderpass_descriptor, - drawable_cb: &sapp.sapp_metal_get_drawable, - }, - d3d11: { - device: sapp.d3d11GetDevice(), - device_context: sapp.d3d11GetDeviceContext(), - render_target_view_cb: &sapp.sapp_d3d11_get_render_target_view, - depth_stencil_view_cb: &sapp.sapp_d3d11_get_depth_stencil_view, - }, - wgpu: { - device: sapp.wgpuGetDevice(), - render_view_cb: &sapp.sapp_wgpu_get_render_view, - resolve_view_cb: &sapp.sapp_wgpu_get_resolve_view, - depth_stencil_view_cb: &sapp.sapp_wgpu_get_depth_stencil_view, - }, - }; - return ctx; +extern(C) sg.Environment sglue_environment() @system @nogc nothrow; +sg.Environment environment() @trusted @nogc nothrow { + return sglue_environment(); +} +extern(C) sg.Swapchain sglue_swapchain() @system @nogc nothrow; +sg.Swapchain swapchain() @trusted @nogc nothrow { + return sglue_swapchain(); } diff --git a/src/sokol/shape.d b/src/sokol/shape.d index ab68495..e827f4f 100644 --- a/src/sokol/shape.d +++ b/src/sokol/shape.d @@ -10,13 +10,13 @@ struct Range { } extern(C) struct Mat4 { - float[4][4] m = 0.0; + float[4][4] m = 0.0f; } extern(C) struct Vertex { - float x = 0.0; - float y = 0.0; - float z = 0.0; + float x = 0.0f; + float y = 0.0f; + float z = 0.0f; uint normal = 0; ushort u = 0; ushort v = 0; @@ -51,8 +51,8 @@ struct Buffer { } extern(C) struct Plane { - float width = 0.0; - float depth = 0.0; + float width = 0.0f; + float depth = 0.0f; ushort tiles = 0; uint color = 0; bool random_colors = false; @@ -61,9 +61,9 @@ struct Plane { } extern(C) struct Box { - float width = 0.0; - float height = 0.0; - float depth = 0.0; + float width = 0.0f; + float height = 0.0f; + float depth = 0.0f; ushort tiles = 0; uint color = 0; bool random_colors = false; @@ -72,7 +72,7 @@ struct Box { } extern(C) struct Sphere { - float radius = 0.0; + float radius = 0.0f; ushort slices = 0; ushort stacks = 0; uint color = 0; @@ -82,8 +82,8 @@ struct Sphere { } extern(C) struct Cylinder { - float radius = 0.0; - float height = 0.0; + float radius = 0.0f; + float height = 0.0f; ushort slices = 0; ushort stacks = 0; uint color = 0; @@ -93,8 +93,8 @@ struct Cylinder { } extern(C) struct Torus { - float radius = 0.0; - float ring_radius = 0.0; + float radius = 0.0f; + float ring_radius = 0.0f; ushort sides = 0; ushort rings = 0; uint color = 0;